如何从 InputStream 转换为 AudioInputStream
Posted
技术标签:
【中文标题】如何从 InputStream 转换为 AudioInputStream【英文标题】:How to cast from InputStream to AudioInputStream 【发布时间】:2012-05-14 22:23:43 【问题描述】:是否可以从 InputStream 转换为 AudioInputStream?
我想在某些活动中播放小声音文件,所以我关注了 SoundThread
import java.io.*;
import javax.sound.sampled.*;
public class SoundThread implements Runnable
private String filename;
SoundThread(String filename)
this.filename = filename;
public void run()
try
InputStream in = ClassLoader.getSystemResourceAsStream("sounds/"+filename+".wav");
Clip clip = Audiosystem.getClip();
clip.open((AudioInputStream)in);
clip.start();
catch (FileNotFoundException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
catch (NullPointerException e)
e.printStackTrace();
catch (LineUnavailableException e)
e.printStackTrace();
我运行它
new Thread(new SoundThread("nameOfTheSoundFile")).start();
一开始我使用 sun.audio.AudioPlayer 和 sun.audio.AudioStream 处理它,但是当我将该代码放入 Eclipse 时,它显示了错误。所以我尝试了
AudioInputStream in = (AudioInputStream)ClassLoader.getSystemResourceAsStream("sounds/"+filename+".wav");
将 InputStream 转换为 AudioInputStream(eclipse 没有显示任何错误),但运行它会引发 ClassCastException。这个问题有什么解决办法吗?
【问题讨论】:
【参考方案1】:使用AudioSystem
直接从URL
获取资源的AudioInputStream
。
URL url = ClassLoader.getResource("/sounds/"+filename+".wav");
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip();
clip.open(ais);
另见AudioSystem.getAudioInputStream(InputStream)
,但这“更危险”。 Java Sound 通常需要一个可重新定位的输入流。出于某种我不太清楚的原因,Class.getResourceAsStream()
变体有时会返回一个非可重新定位的流。
【讨论】:
@Stephen C 我尝试了两种方法,一次是通过 URL 截取上面的代码,另一个是 AudioSystem.getAudioInputStream(ClassLoader.getSystemResourceAsStream("sounds/"+filename+".wav"))。在这两种方式中,代码都会通过,但不会播放任何声音。我还尝试从 cmd 启动它(没有类加载器的原始代码工作),但也没有声音。但尤其是第二个我不明白:它与原始代码中的方式完全相同,只是我不直接创建 AudioInputStream,而是通过 ClassLoader 和 .getAudioInputStream(InputStream) OK - 退后一步,试试Java Sound info. page 上显示的确切代码 - “LoopSound” 源代码。 1) 该代码是否适用于我网站上的原始循环 WAV? 2) 如果您将 URL 更改为指向您的 WAV,该代码是否有效? 3)如果不是,它会产生什么输出? Number 1) 在 Eclipse 中工作正常。编号 2) 也是,但是由于在静态方法中我无法生成 'getClass().getResource("/sounds/"check.wav")',因此我必须在 URL 'url = LoopSound.class 中更改它。 getResource("/sounds/check.wav")'; 当我现在复制我的类 SoundThread 中的确切代码时,声音不是格子花呢。主要区别在于,在您的代码中,我们使用了 'invokeLater()' 方法,而在我的代码中,整个类被扩展为可运行。这有什么影响? 这是现在可行的解决方案。非常感谢您编辑:我在这里发布了一些代码,但看起来非常糟糕。我只是不使用 runnable 实现类并创建一个SwingUtilities.invokeLater()
(它是空的),一切都很好【参考方案2】:
你不能施放它。在 Java 中,仅当您要转换的真实对象已经是目标类型的一个实例时,才能对引用类型进行类型转换。例如:
String myString = new String("42");
Object obj = (Object) myString; // OK
String mystery = (String) obj; // OK
String mystery2 = (Integer) obj; // FAIL
前两个成功是因为我们在第一行创建的字符串对象是Object
的实例(因为String
是Object
的子类型),以及String
的实例。第三个失败,因为 String
不是 Integer
。
在您的示例中,您从getSystemResourceAsStream
获得的对象是包含(可能)音频数据的原始流。它不是音频流;即不是AudioInputStream
的实例。
您必须包装原始输入流,如下所示:
InputStream in = ClassLoader.getSystemResourceAsStream(
"sounds/"+filename+".wav");
AudioFormat format = ...
int length = ...
AudioInputStream audio = new AudioInputStream(in, format, length);
或使用AudioSystem.getAudioInputStream(...)
工厂方法之一,它在引擎盖下进行包装。
有关正确方法的详细信息,请参阅 Andrew Thomson 的回答。
【讨论】:
@Andrew Thompson 我刚刚看到您在发表我的评论后对您的帖子进行的编辑。我想尝试使用 AudioFormat 和长度编辑您的解决方案,但即使阅读 API,我也不太明白在哪里找到分别创建 AudioFormat 长度的参数。我想(因为我们还没有创建“声音文件”),没有我可以使用的 .getSampleBitRate() 方法,对吗?如何获得正确的参数? @ValentinoRu - 我>>推荐getAudioInputStream 方法的代码以了解如何形成所需的参数。 @ValentinoRu - 我的答案的真正意义在于解释铸造在 Java 中是如何工作的,以及(因此)为什么你不能通过铸造来解决这个问题。【参考方案3】:getSystemResourceAsStream
返回的 InputStream
不是 AudioInputStream
,因此强制转换它永远不会起作用。只需创建一个新的AudioInputStream
。
【讨论】:
以上是关于如何从 InputStream 转换为 AudioInputStream的主要内容,如果未能解决你的问题,请参考以下文章
如何将 inputsource 转换为 inputstream 并将其作为参数提供给 stringreader?
如何从 JsonObject 创建 InputStream 对象
如何在 Java 中将 String[] 数组转换为 InputStream
如何在 Java 中将 InputStream 转换为字符串?