我在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)
显然问题是正在选择PulseAudio混音器,并且由于某种原因它无法播放.wav文件。
如果我将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赫兹?
答案 0 :(得分:1)
如果您能够在用例中使用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)
,直到有效。
另一种方法是循环Mixer.Info
返回的AudioSystem.getMixerInfo()
个对象。每次调用AudioSystem.getMixer(mixerInfo)
以获取Mixer
实例。循环遍历Line.Info
返回的Mixer.getSourceLineInfo()
个对象。对于其中的每一个,如果它是DataLine.Info
的实例,请将其强制转换并调用DataLine.Info.getFormats()
以获取受支持的AudioFormat
对象。将这些与AudioInputStream.getFormat()
返回的内容(使用matches
)进行比较,直至找到兼容的内容。
这些都不是特别优雅。第一个是对异常的错误使用。第二个只是有点复杂,虽然看起来更正确。
答案 1 :(得分:1)
我也在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();
}
}
如何确保选择兼容的混音器?
另一种情况 - 默认使用默认值,或者捕获异常并在故障转移时使用默认值。
答案 2 :(得分:0)
看起来这里涉及两个不同的问题。
首先,依赖AudioSystem.getClip()
并不是一个好主意,因为基本上不能保证剪辑能够处理wav文件的特定格式。相反,应使用以下方法之一:
As suggested by @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);
[...]
}
或者,as suggested by @egorlitvinenko,使用AudioSystem.getLine(DataLine.Info)
获取具有所需功能的行。
上述两种方法都应该“有效”。
最重要的是,PulseAudio还有一个问题,就是有一个错误可能会导致“无效格式”异常,即使PulseAudio混音器实际上可以处理格式 。这在以下错误报告中描述(第二个包含解决方法):