Java声音API在播放音频文件后锁定该文件。

huangapple go评论73阅读模式
英文:

Java Sound API locks audio file after playing it

问题

我正在尝试使用Javax.sound播放一个.wav文件
一切运行正常文件按预期播放最后我关闭了Clip和AudioInputStream然而在此之后文件仍然被锁定在使用中),我无法在不获得异常的情况下触摸它java.nio.file.FileSystemException: alerting.wav: 进程无法访问该文件因为它正在被另一个进程使用

下面是代码示例

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 无法播放警报声音", ex);
            } finally {
                inputStream.close();
            }
        } catch (UnsupportedAudioFileException ex) {
            Main.syslog(Level.WARNING, "E1001 无法播放警报声音", ex);
        } catch (IOException ex) {
            Main.syslog(Level.WARNING, "E1001 无法播放警报声音", 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();
    }
}

在Java线程列表中,我看到“Java Sound Event Dispatcher”正在运行。我认为这是导致文件被锁定的原因。
您有什么办法可以解决这个问题吗?谢谢


<details>
<summary>英文:</summary>
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(&quot;alerting.wav&quot;);
try {
inputStream = AudioSystem.getAudioInputStream(soundFile);
try {
clip = AudioSystem.getClip();
clip.addLineListener(this);
clip.open(inputStream);
while(cycles &gt; 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(&quot;All closed&quot;);
try {
this.finalize();
} catch (Throwable ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (Exception ex) {
Main.syslog(Level.WARNING, &quot;E1001 could not play alert sound&quot;, ex);
} finally {
inputStream.close();
}
} catch (UnsupportedAudioFileException ex) {
Main.syslog(Level.WARNING, &quot;E1001 could not play alert sound&quot;, ex);
} catch (IOException ex) {
Main.syslog(Level.WARNING, &quot;E1001 could not play alert sound&quot;, ex);
}
}
@Override
public void update(LineEvent event) {
LineEvent.Type type = event.getType();
System.out.println(&quot;Event: &quot; + type);
if(type == LineEvent.Type.STOP) {
playCompleted = true;
} else if (type == LineEvent.Type.CLOSE) {
System.out.println(&quot;listener closed&quot;);
}
}
}
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 &quot;Java Sound Event Dispatcher&quot; running. I think this is what keeps the file locked.
Any idea how can I fix this? Thanks
</details>
# 答案1
**得分**: 1
The API for Clip states:
&gt; 注意,一些一旦关闭的线路将无法重新打开。尝试重新打开这种线路将始终导致 `LineUnavailableException`。
我将提出几点额外的建议。
与其使用 `File`,更好的加载音频资源的方法是使用 `class.getResource` 方法。这个方法会返回一个 `URL`,你可以将其作为参数传递给 `AudioSystem.getAudioInputStream` 方法。
我不清楚你试图做什么,但我还建议对你的代码进行进一步的更改。在同一个方法中初始化和播放 `Clip` 通常是不推荐的,因为这违反了 `Clip` 的预期用途。`Clip` 适用于可以保存在内存中的声音。所以,将你的 `Clip` 声明为实例变量。然后,将加载和打开 `Clip` 的代码放在它自己的方法中。并且将调用 `start` 或 `loop` 的代码放在单独的方法中,除非你确定不会再次播放它,否则不要在播放结束时关闭 `Clip`。
如果使用 `clip.loop`,你就不必担心监听器和迭代次数。
<details>
<summary>英文:</summary>
The API for Clip states: 
&gt; Note that some lines, once closed, cannot be reopened. Attempts to
&gt; reopen such a line will always result in a `LineUnavailableException`.
I&#39;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&#39;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&#39;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&#39;t have to bother with listeners and count iterations.
</details>
# 答案2
**得分**: 0
替代方式:
```java
//...
AudioInputStream inputStream;
File soundFile = new File("alerting.wav");
try {
byte[] bytes = Files.readAllBytes(soundFile.toPath());
inputStream = AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes));
// ...
}
// ...
英文:

Instead of:

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

Try this:

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

huangapple
  • 本文由 发表于 2020年8月30日 02:42:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63650594.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定