簡體   English   中英

Java音頻無法在Linux中播放WAV文件

[英]Java audio fails to play wav file in Linux

我在Linux上使用Java音頻時遇到問題。 這是Ubuntu 14.04上的OpenJDK 8。 以下示例因此鏈接中的.wav文件而失敗:

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)

顯然問題在於選擇了PulseAudio混音器,並且由於某種原因它無法播放.wav文件。

如果我將AudioSystem.getClip()調用替換為AudioSystem.getClip() AudioSystem.getClip(null) ,它將選擇默認的混音器,那么它將起作用。

如何確定選擇了兼容的調音台?


更新:遵循@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?

如果您可以在用例中使用SourceDataLine而不是Clip ,則應該可以執行以下操作:

    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 正如您所注意到的, AudioSystem.getClip()的語義不是特別可靠。 在try / catch中包裝所有調用Clip.open的嘗試。 如果打開剪輯不適用於默認的混音器,請遍歷除默認值之外的可用Mixer.Info對象, getClip(mixerInfo)每個對象分別調用getClip(mixerInfo)直到一個getClip(mixerInfo)

另一種方法是遍歷AudioSystem.getMixerInfo()返回的Mixer.Info對象。 AudioSystem.getMixer(mixerInfo)為每個調用AudioSystem.getMixer(mixerInfo)以獲取Mixer實例。 循環瀏覽由Mixer.getSourceLineInfo()返回的Line.Info對象。 對於每一個,如果它是DataLine.Info的實例,則將其DataLine.Info並調用DataLine.Info.getFormats()以獲取受支持的AudioFormat對象。 比較這些反對什么AudioInputStream.getFormat()返回(使用matches ),直到你找到一個兼容的一個。

這些都不是特別優雅。 首先是對異常的錯誤使用。 第二個似乎有點令人費解,盡管看起來更正確。

我也在Ubuntu 14.04上,但是有不同的混音器,它工作正常。 我認為您可以指定具體的參數,這是您的生產線所需要的:

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

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();
        try {
            AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                    44100,
                    16, 2, 4,
                    AudioSystem.NOT_SPECIFIED, true);
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            clip = (Clip) AudioSystem.getLine(info);
        } catch (LineUnavailableException e) {
            System.out.println("matching line is not available due to resource restrictions");
            return;
        } catch (SecurityException ee) {
            System.out.println("if a matching line is not available due to security restrictions");
            return;
        } catch (IllegalArgumentException eee) {
            System.out.println("if the system does not support at least one line matching the specified Line.Info object " +
                    "through any installed mixer");
            return;
        }
        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();
    }
}

如何確定選擇了兼容的調音台?

另一種情況-默認情況下使用默認值,或者捕獲異常並在故障轉移時使用默認值。

看起來這里涉及兩個獨立的問題。

首先,依賴AudioSystem.getClip()並不是一個好主意,因為基本上不能保證該剪輯將能夠處理wav文件的特定格式。 而是,應使用以下方法之一:

  • 正如@Dave所建議的那樣 :循環瀏覽可用的混音器並查詢是否支持目標格式:

     URL url = getClass().getResource("drop.wav"); AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(url); AudioFormat format = audioInputStream.getFormat(); DataLine.Info lineInfo = new DataLine.Info(Clip.class, format); Mixer.Info selectedMixer = null; for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) { Mixer mixer = AudioSystem.getMixer(mixerInfo); if (mixer.isLineSupported(lineInfo)) { selectedMixer = mixerInfo; break; } } if (selectedMixer != null) { Clip clip = AudioSystem.getClip(selectedMixer); [...] } 
  • 或者, 按照@egorlitvinenko的建議 ,使用AudioSystem.getLine(DataLine.Info)獲得具有所需功能的線路。

以上兩種方法都“應該”起作用。

最重要的是,PulseAudio還存在另一個問題,即存在一個錯誤, 即使PulseAudio混合器可以實際處理格式 ,該錯誤也可能導致“無效格式”異常。 以下錯誤報告對此進行了描述(第二個報告包含解決方法):

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM