Eclipse IDE中可以播放音频文件,但打成JAR文件后却不能播放。

3
我正在使用的音频文件在这里找到:http://www.orangefreesounds.com/loud-alarm-clock-sound/ 在我的Eclipse IDE中,我的文件结构如下所示: What my file structure looks like 当我在IDE中运行它时,音频文件可以正常播放,但是当我将其导出为JAR文件时却不能播放。我已经检查并发现音频文件在JAR文件中。
我使用终端命令java -jar Sandbox.jar &来运行JAR文件。程序似乎能够找到文件(因为它没有抛出IOException),但似乎无法执行播放。
为什么会出现这个问题,我该如何解决?
奇怪的更新
好吧,实际上,在Windows 8.1的cmdPowerShell中运行JAR文件时,它可以播放音频文件,但在Ubuntu 14.04的终端中却不能播放。整个时间,我一直在尝试在Ubuntu 14.04中运行JAR文件。
奇怪的更新#2
我确认JAR文件只能在Windows 8.1系统上工作。本问题中的两个代码片段都无法工作,而MadProgrammer的两个解决方案都可以工作。
最小、完整和可验证的示例(在Windows或Ubuntu上都无法工作)
import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.*;

public class Sandbox
{

    public static void main(String[] args) throws UnsupportedAudioFileException, IOException, LineUnavailableException
    {
        URL url = Sandbox.class.getResource("/sound-effects/alarmSoundClip.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(url);
        AudioFormat af = ais.getFormat();
        DataLine.Info info = new DataLine.Info(Clip.class, af);

        Clip clip = (Clip) AudioSystem.getLine(info);
        clip.open(ais);
        clip.start();
    }

}

尝试解决方案#1(在Windows或Ubuntu上不起作用)

一个尝试的解决方案(由Andrew Thompson建议)是使用this.getClass().getResource( ... )而不是Sandbox.class.getResource( ... ):

import java.io.IOException;
import java.net.URL;

import javax.sound.sampled.*;

public class Sandbox
{

    public static void main(String[] args) throws UnsupportedAudioFileException, IOException, LineUnavailableException
    {
        new Sandbox();
    }

    public Sandbox() throws UnsupportedAudioFileException, IOException, LineUnavailableException
    {
        URL url = this.getClass().getResource("/sound-effects/alarmSoundClip.wav");
        AudioInputStream ais = AudioSystem.getAudioInputStream(url);
        AudioFormat af = ais.getFormat();
        DataLine.Info info = new DataLine.Info(Clip.class, af);

        Clip clip = (Clip) AudioSystem.getLine(info);
        clip.open(ais);
        clip.start();
    }
}

URL url = Sandbox.class.getResource("/sound-effects/alarmSoundClip.wav"); 可能会获取错误的类加载器。重新排列代码,使其可以表达为 URL url = this.getCass().getResource("/sound-effects/alarmSoundClip.wav");。其中一种方法是将该语句移动到 Sandbox 构造函数中。 - Andrew Thompson
@AndrewThompson 当作为JAR运行时仍然无法工作。我将编辑我的答案以包含您的解决方案。 - zxgear
clip.start 后添加 clip.drain()clip.start 不是阻塞方法,因此它会启动另一个线程,这可能会导致 JVM 在退出 main 方法后立即终止。 - MadProgrammer
@MadProgrammer 我的 IDE 中仍然可以播放音频,但在 JAR 文件中无法播放。 - zxgear
@JohnH 请尝试使用 java -jar Sandbox.jar 命令运行(不要加上 &...) - MadProgrammer
显示剩余6条评论
1个回答

1

clip.start()之后添加clip.drain()似乎对我来说效果不错(使用IDE和命令行都可以,有无&都可以)

import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Sandbox {

    public static void main(String[] args)  {
        try {
            URL url = Sandbox.class.getResource("/sound-effects/Loud-alarm-clock-sound.wav");
            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
            AudioFormat af = ais.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, af);

            Clip clip = (Clip) AudioSystem.getLine(info);
            clip.open(ais);
            clip.start();
            System.out.println("Drain...");
            clip.drain();
            System.out.println("...Drained");
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException exp) {
            exp.printStackTrace();
        }
    }

}

现在,话虽如此,但我发现在过去中drain有点不可靠,特别是当有多个声音播放的时候,我倾向于使用LineListener
例如...
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;

public class Sandbox {

    protected static final Object LOCK = new Object();

    public static void main(String[] args) {
        try {
            URL url = Sandbox.class.getResource("/sound-effects/Loud-alarm-clock-sound.wav");
            AudioInputStream ais = AudioSystem.getAudioInputStream(url);
            AudioFormat af = ais.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, af);

            Clip clip = (Clip) AudioSystem.getLine(info);
            clip.open(ais);

            clip.addLineListener(new LineListener() {
                @Override
                public void update(LineEvent event) {
                    System.out.println(event.getType());
                    if (event.getType() == LineEvent.Type.STOP) {
                        synchronized (LOCK) {
                            LOCK.notify();
                        }
                    }
                }
            });
            clip.start();

            synchronized (LOCK) {
                LOCK.wait();
            }
        } catch (UnsupportedAudioFileException | IOException | LineUnavailableException | InterruptedException exp) {
            exp.printStackTrace();
        }
    }

}

@JohnH 使用 LineListener 代替(虽然在调用 Clip#start 之前可能可以调用 Clip#flush 来测试 Clip#drain)。 - MadProgrammer
真的吗?看起来还不错。 - MadProgrammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接