1

I am trying to use Javax.sound to play a .wav file. Everything works fine, the file plays as expected and in the end I close the Clip and I close the AudioInputStream. However, the file remains locked (in use) after that and I cannot touch it without getting an exception: java.nio.file.FileSystemException: alerting.wav: The process cannot access the file because it is being used by another process.

A sample of code is below:

static private class SoundThread extends Thread implements LineListener {
    private boolean playCompleted;
    private int cycles;
    
    public SoundThread(int repeats) {
        cycles = repeats;
    }
    
    @Override
    public void run() {
        Clip clip;
        AudioInputStream inputStream;
        File soundFile = new File("alerting.wav");
        try {
            inputStream = AudioSystem.getAudioInputStream(soundFile);
            try {
                clip = AudioSystem.getClip();
                clip.addLineListener(this);
                clip.open(inputStream);
                while(cycles > 0) {
                    playCompleted = false;
                    clip.setFramePosition(0);
                    clip.start();
                    while(!playCompleted) {
                        Thread.sleep(1000);
                    }
                    Thread.sleep(audioRepeatTime * 1000);
                    cycles--;
                }
                //clip.drain();
                clip.close();
                inputStream.close();
                System.out.println("All closed");
                try {
                    this.finalize();
                } catch (Throwable ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (Exception ex) {
                Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
            } finally {
                inputStream.close();
            }
        } catch (UnsupportedAudioFileException ex) {
            Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
        } catch (IOException ex) {
            Main.syslog(Level.WARNING, "E1001 could not play alert sound", ex);
        }
    }

    @Override
    public void update(LineEvent event) {
        LineEvent.Type type = event.getType();
        
        System.out.println("Event: " + type);
        if(type == LineEvent.Type.STOP) {
            playCompleted = true;
        } else if (type == LineEvent.Type.CLOSE) {
            System.out.println("listener closed");
        }
    }
}

public static void PlayAlertSound() {
    if(enableAudio) {
        SoundThread st = new SoundThread(audioLoops);
        st.start();
    }
} 

public static void PlayAlertSound(int repeats) {
    if(enableAudio) {
        SoundThread st = new SoundThread(repeats);
        st.start();
    }
} 

In the Java threads list I see "Java Sound Event Dispatcher" running. I think this is what keeps the file locked. Any idea how can I fix this? Thanks

2 Answers2

1

The API for Clip states:

Note that some lines, once closed, cannot be reopened. Attempts to reopen such a line will always result in a LineUnavailableException.

I'm going to make a couple additional suggestions.

Instead of using File, a better way to load audio resources is with the class.getResource method. This method returns a URL which you can then pass as your argument to the AudioSystem.getAudioInputStream method.

I'm not clear what you are trying to do, but I also recommend some further changes to your code. Initializing and playing a Clip in the same method is not generally done, as it goes against the intended use of the Clip. A Clip is meant for sounds that can be held in memory. So, make your Clip an instance variable. Then, place the code that loads and opens the Clip in its own method. And put the code that calls start or loop in a separate method or methods, and don't close the Clip at the end of playing unless you are sure you are not going to ever play it again.

If you use clip.loop, you don't have to bother with listeners and count iterations.

Phil Freihofner
  • 7,645
  • 1
  • 20
  • 41
  • Thanks for the answer. I don't have any problems with playing sound, that works fine. My problem is that when I don't play the sound and everything is closed, the file is still locked by the system and cannot be modified or deleted. I just want to be able, in some other dialog window, to load a different .wav form computer and save it with same name as initial file. It looks like AudioInputStream still locks the file although I closed it. I also tried to use Media and MediaPlayer but same thing happens. – Adrian Bica Aug 30 '20 at 03:27
  • Maybe the File command is holding on. Try using URL instead. I just noticed you are doing everything within a "sound thread". It's rarely needed to handle sounds--new threads are launched every time a sound is played. Sorry I can't help more but the way you are doing things is confusing to me. I think simplifying would go a long way to solving your issue. Maybe try just making a simple Clip, call it, play it, let it get garbage-collected, and then see if you can load the file. I know I've loaded files wav files multiple times in the past, but always with their own AudioInputStreams. – Phil Freihofner Aug 30 '20 at 05:28
  • This is a part of very complex program, it is not a sound player. This is why I am using a thread. The program has to run and doing its job and sometimes it has to play a sound for a programmed number of times at some configurable intervals without holding the whole program. However, I tried just to play sound without thread only once. Once the file was played, it becomes "in use by other process" and cannot be touched anymore. Thanks – Adrian Bica Aug 30 '20 at 12:57
  • This is same as this topic: https://stackoverflow.com/questions/11316289/cannot-delete-file-even-after-closing-audioinputstream which never got a right answer – Adrian Bica Aug 30 '20 at 13:15
0

Instead of:

//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
    inputStream = AudioSystem.getAudioInputStream(soundFile);
    // ...
}
// ...

Try this:

//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
    byte[] bytes = Files.readAllBytes(soundFile.toPath());
    inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
    // ...
}
// ...