#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    6
    Rep Power
    0

    Java audio NullPointerException/Stream Closed exception


    I am trying to add sound to a game I am making, but every time I try to play the sound, I get a NullPointerException. The file is named correctly, so I don't understand why this is happening.

    Loads the sound:

    Code:
      public class WavPlayer extends Thread {
    
        /*
         * @param s The path of the wav file.
         * @return The sound data loaded into the WavSound object
         */
        public static WavSound loadSound(String s){
            // Get an input stream
            InputStream is = WavPlayer.class.getClassLoader().getResourceAsStream(s);
            AudioInputStream audioStream;
            try {
                // Buffer the input stream
                BufferedInputStream bis = new BufferedInputStream(is);
                // Create the audio input stream and audio format
                audioStream = AudioSystem.getAudioInputStream(bis);
                AudioFormat format = audioStream.getFormat();
                // The length of the audio file
                int length = (int) (audioStream.getFrameLength() * format.getFrameSize());
                // The array to store the samples in
                byte[] samples = new byte[length];
                // Read the samples into array to reduce disk access
                // (fast-execution)
                DataInputStream dis = new DataInputStream(audioStream);
                dis.readFully(samples);
                // Create a sound container
                WavSound sound = new WavSound(samples, format, (int) audioStream.getFrameLength());
                // Don't start the sound on load
                sound.setState(SoundState.STATE_STOPPED);
                // Create a new player for each sound
                new WavPlayer(sound);
                return sound;
            } catch (Exception e) {
                // An error. Mustn't happen
            }
            return null;
        }
    
        // Private variables
        private WavSound sound = null;
    
        /**
         * Constructs a new player with a sound and with an optional looping
         * 
         * @param s The WavSound object
         */
        public WavPlayer(WavSound s) {
            sound = s;
            start();
        }
    
        /**
         * Runs the player in a separate thread
         */
        @Override
        public void run(){
            // Get the byte samples from the container
            byte[] data = sound.getData();
            InputStream is = new ByteArrayInputStream(data);
            try {
                // Create a line for the required audio format
                SourceDataLine line = null;
                AudioFormat format = sound.getAudioFormat();
                // Calculate the buffer size and create the buffer
                int bufferSize = sound.getLength();
                // System.out.println(bufferSize);
                byte[] buffer = new byte[bufferSize];
                // Create a new data line to write the samples onto
                DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
                line = (SourceDataLine) AudioSystem.getLine(info);
                // Open and start playing on the line
                try {
                    if (!line.isOpen()) {
                        line.open();
                    }
                    line.start();
                } catch (Exception e){}
                // The total bytes read
                int numBytesRead = 0;
                boolean running = true;
                while (running) {
                    // Destroy this player if the sound is destroyed
                    if (sound.getState() == SoundState.STATE_DESTROYED) {
                        running = false;
                        // Release the line and release any resources used
                        line.drain();
                        line.close();
                    }
                    // Write the data only if the sound is playing or looping
                    if ((sound.getState() == SoundState.STATE_PLAYING)
                            || (sound.getState() == SoundState.STATE_LOOPING)) {
                        numBytesRead = is.read(buffer, 0, buffer.length);
                        if (numBytesRead != -1) {
                            line.write(buffer, 0, numBytesRead);
                        } else {
                            // The samples are ended. So reset the position of the
                            // stream
                            is.reset();
                            // If the sound is not looping, stop it
                            if (sound.getState() == SoundState.STATE_PLAYING) {
                                sound.setState(SoundState.STATE_STOPPED);
                            }
                        }
                    } else {
                        // Not playing. so wait for a few moments
                        Thread.sleep(Math.min(1000 / Global.FRAMES_PER_SECOND, 10));
                    }
                }
            } catch (Exception e) {
                // Do nothing
            }
        }
    The method play() is in this class:

    Code:
    public class WavSound {
    
        // Private variables
        private byte[] data = null;
        private AudioFormat format = null;
    
        private int length = 0;
    
        private boolean loop = false;
        private SoundState state = SoundState.STATE_STOPPED;
    
        /**
         * Constructs a new WavSound with a specific AudioFormat and sound data
         * 
         * @param data The data of the WAV file as a byte array.
         * @param format The format of this WAV file.
         */
        public WavSound(byte[] data, AudioFormat format, int length) {
            this.data = data;
            this.format = format;
            this.length = length;
        }
    
        /**
         * Returns the data associated with this WavSound
         * 
         * @return The data as a byte array
         */
        public byte[] getData(){
            return data;
        }
    
        /**
         * Returns the audio format used by this WavSound
         * 
         * @return The audio format used
         */
        public AudioFormat getAudioFormat(){
            return format;
        }
    
        /**
         * Returns the current state of the sound
         * 
         * @return The current sound state
         */
        public SoundState getState(){
            return state;
        }
    
        /**
         * Sets the state of this sound
         * 
         * @param state The SoundState describing the state
         */
        public void setState(SoundState state){
            this.state = state;
        }
    
        /**
         * Returns true if this sound is playing or looping
         * 
         * @return True if this sound is playing
         */
        public boolean isPlaying(){
            return (state == SoundState.STATE_PLAYING || state == SoundState.STATE_LOOPING);
        }
    
        /**
         * Stops the current sound
         */
        public void stop(){
            state = SoundState.STATE_STOPPED;
        }
    
        /**
         * Play's the current sound
         */
        public void play(){
            if (loop) {
                state = SoundState.STATE_LOOPING;
            } else {
                state = SoundState.STATE_PLAYING;
            }
        }
    
        /**
         * Destroy's this sound so that it can't be played
         */
        public void destroy(){
            state = SoundState.STATE_DESTROYED;
        }
    
        /**
         * Checks if this sound is looping
         * 
         * @return True if looping else false
         */
        public boolean isLooping(){
            return loop;
        }
    
        /**
         * Set's the looping value of this sound
         * 
         * @param value
         */
        public void setLooping(boolean value){
            loop = value;
        }
    
        public int getLength(){
            return length;
        }
    I'm loading the sound in my main class using
    Code:
    WavPlayer sound1 = WavPlayer.loadSound("coin.wav");
    and playing it using
    Code:
    sound1.play();
    I get the NullPointer when I call the play() method. What am I doing wrong?
  2. #2
  3. Lord of the Dance
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2003
    Posts
    3,707
    Rep Power
    1959
    You are not doing anything in you catch, you should at least print out the error message from the exception, especially during development.
    Right now, your function just return null if something goes wrong.
    And that is why you get the null pointer exception.

    Furthermore, if you know something can return null, you should always validate if it did return null.

    Generally, when you get any error messages, you should try to post (copy/paste) the exact error message you got.
    Last edited by MrFujin; October 5th, 2013 at 08:53 PM.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    6
    Rep Power
    0
    Originally Posted by MrFujin
    You are not doing anything in you catch, you should at least print out the error message from the exception, especially during development.
    Right now, your function just return null if something goes wrong.
    And that is why you get the null pointer exception.

    Furthermore, if you know something can return null, you should always validate if it did return null.

    Generally, when you get any error messages, you should try to post (copy/paste) the exact error message you got.
    Okay, I tried this and the error I got was "Stream closed."
    And I still got the null pointer exception.
    Here's the null pointer:
    "Error: Stream closed

    Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at stm.STM.paint(STM.java:903) //This is the line where I call the play() method.
    at java.awt.Container.update(Container.java:1834)
    at sun.awt.RepaintArea.updateComponent(RepaintArea.java:267)
    at sun.awt.RepaintArea.paint(RepaintArea.java:233)
    at apple.awt.ComponentModel.handleEvent(ComponentModel.java:263)
    at java.awt.Component.dispatchEventImpl(Component.java:4852)
    at java.awt.Container.dispatchEventImpl(Container.java:2141)
    at java.awt.Component.dispatchEvent(Component.java:4604)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:717)
    at java.awt.EventQueue.access$400(EventQueue.java:82)
    at java.awt.EventQueue$2.run(EventQueue.java:676)
    at java.awt.EventQueue$2.run(EventQueue.java:674)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:690)
    at java.awt.EventQueue$3.run(EventQueue.java:688)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:86)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:687)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)"

    And, if it helps, the error "stream closed" occurred in WavPlayer.loadSound().
  6. #4
  7. Lord of the Dance
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2003
    Posts
    3,707
    Rep Power
    1959
    You have this line in loadSound:
    Code:
    new WavPlayer(sound);
    What exactly do you want to do with this?

    Your code does not refer to anything in WavPlayer.
    Can you post the code you added to the the catch block in the loadSound function?
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    8
    Rep Power
    0
    There are also 2 declarations of WavSound sound - one inside loadSound and one declared as a private member variable to wave player. Even if the code works, it will be confusing to maintain.

    Also, we don't know from this code it is not obvious what is happening to the sound variable which gets returned from loadSound. That variable gets passed into the new thread and used in run. Just ensure that what happens to the various streams in the first thread won't adversely impact the new thread.
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2013
    Posts
    6
    Rep Power
    0
    Originally Posted by djslavens
    There are also 2 declarations of WavSound sound - one inside loadSound and one declared as a private member variable to wave player. Even if the code works, it will be confusing to maintain.

    Also, we don't know from this code it is not obvious what is happening to the sound variable which gets returned from loadSound. That variable gets passed into the new thread and used in run. Just ensure that what happens to the various streams in the first thread won't adversely impact the new thread.
    I got rid of the
    Code:
    new WavPlayer(sound);
    . I don't get the null pointer anymore, just the stream closed exception.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2013
    Posts
    8
    Rep Power
    0
    Some progress - that's good! The variables like dis and bis are local to loadSound so it's probably the case the loadSound returns and they go out of scope and are not available inside of run(). Why don't you try declaring them as member variables of the class WavePlayer continue to init them inside loadSound and see if that helps.

    Also understand though, that if you create additional threads beyond the first one that access those variables, you will have to do additional work to protect them and prevent conditions like race and deadlock.

IMN logo majestic logo threadwatch logo seochat tools logo