有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java audio无法在Linux中播放wav文件

我在Linux上使用Java音频时遇到问题。这是Ubuntu 14.04上的OpenJDK 8。下面的示例失败。wav文件from this link

import java.net.URL;
import javax.sound.sampled.*;

public class PlaySound {

    public void play() throws Exception
    {
        // List all mixers and default mixer
        System.out.println("All mixers:");
        for (Mixer.Info m : AudioSystem.getMixerInfo())
        {
            System.out.println("    " + m);
        }

        System.out.println("Default mixer: " + AudioSystem.getMixer(null).getMixerInfo());

        URL url = getClass().getResource("drop.wav");
        Clip clip;

        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
        clip = AudioSystem.getClip();
        System.out.println("Clip format: " + clip.getFormat());
        clip.open(audioInputStream);

        clip.start();
        do { Thread.sleep(100); } while (clip.isRunning());
    }

    public static void main(String [] args) throws Exception {
        (new PlaySound()).play();
    }
}

结果是:

All mixers:
    PulseAudio Mixer, version 0.02
    default [default], version 4.4.0-31-generic
    Intel [plughw:0,0], version 4.4.0-31-generic
    Intel [plughw:0,2], version 4.4.0-31-generic
    NVidia [plughw:1,3], version 4.4.0-31-generic
    NVidia [plughw:1,7], version 4.4.0-31-generic
    NVidia [plughw:1,8], version 4.4.0-31-generic
    NVidia [plughw:1,9], version 4.4.0-31-generic
    Port Intel [hw:0], version 4.4.0-31-generic
    Port NVidia [hw:1], version 4.4.0-31-generic
Default mixer: default [default], version 4.4.0-31-generic
Clip format: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian
Exception in thread "main" java.lang.IllegalArgumentException: Invalid format
    at org.classpath.icedtea.pulseaudio.PulseAudioDataLine.createStream(PulseAudioDataLine.java:142)
    at org.classpath.icedtea.pulseaudio.PulseAudioDataLine.open(PulseAudioDataLine.java:99)
    at org.classpath.icedtea.pulseaudio.PulseAudioDataLine.open(PulseAudioDataLine.java:283)
    at org.classpath.icedtea.pulseaudio.PulseAudioClip.open(PulseAudioClip.java:402)
    at org.classpath.icedtea.pulseaudio.PulseAudioClip.open(PulseAudioClip.java:453)
    at PlaySound.play(PlaySound.java:22)
    at PlaySound.main(PlaySound.java:29)

显然,问题是PulseaAudio混音器正在被选中,由于某些原因,它无法播放音乐。wav文件

如果我用AudioSystem.getClip(null)替换AudioSystem.getClip()调用,选择默认的混音器,那么它就可以工作了

如何确保选择了兼容的混音器


更新:按照@Dave的建议,循环使用可用的混音器,直到找到一个具有“兼容”格式的混音器,我看到以下内容:

目标格式(从AudioInputStream.getFormat())是:

PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian

我遍历所有混音器、每个混音器的源代码行,以及每个源代码行支持的格式,并获得以下匹配:

Mixer: PulseAudio Mixer, version 0.02
Source line: interface SourceDataLine supporting 42 audio formats, and buffers of 0 to 1000000 bytes
Format matches: PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian

确实得到了一个匹配(使用format.matches()),但我仍然得到了“无效格式”异常。也许是因为匹配的格式显示“未知采样率”,然后当我尝试打开剪辑时,它发现它实际上不支持44100 Hz


共 (1) 个答案

  1. # 1 楼答案

    如果您能够在用例中使用^{}而不是^{},那么您应该能够执行以下操作:

        URL url = getClass().getResource("drop.wav");
        SourceDataLine sourceLine;
    
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url);
        sourceLine = AudioSystem.getSourceDataLine(audioInputStream.getFormat());
        System.out.println("Source format: " + sourceLine.getFormat());
        sourceLine.open(audioInputStream);
    
        sourceLine.start();
        do { Thread.sleep(100); } while (sourceLine.isRunning());
    

    (注意,这在我这方面还没有经过测试。)

    如果你计划寻找或循环,你只需要Clip

    如果您确实需要查找或循环的功能,一个(丑陋的)方法是首先调用AudioSystem.getClip(null),以确保您选择的是默认的Mixer。{}的语义(正如您所注意到的)并不特别可靠。将调用Clip.open的所有尝试包装在try/catch中。如果使用默认混合器打开剪辑不起作用,则循环使用除默认对象之外的可用Mixer.Info对象,并对每个对象调用getClip(mixerInfo),直到其中一个起作用

    另一种方法是循环通过AudioSystem.getMixerInfo()返回的Mixer.Info对象。为每个调用AudioSystem.getMixer(mixerInfo)以获取Mixer实例。循环遍历Mixer.getSourceLineInfo()返回的Line.Info对象。对于其中的每一个,如果它是DataLine.Info的实例,则强制转换它并调用DataLine.Info.getFormats()以获取支持的AudioFormat对象。将它们与AudioInputStream.getFormat()返回的内容进行比较(使用matches),直到找到一个兼容的

    这两个都不是特别优雅。第一个是异常的错误使用。第二种方法有点复杂,尽管它似乎更正确