为什么这段代码不播放声音文件

代码

import javax.sound.sampled.*; import java.io.*; public class Tester { static Thread th; public static void main(String[] args) { startNewThread(); while( th.isAlive() == true) { System.out.println("sound thread is working"); } } public static void startNewThread() { Runnable r = new Runnable() { public void run() { startPlaying(); } }; th =new Thread(r); th.start(); } public static void startPlaying() { try { AudioInputStream ais = AudioSystem.getAudioInputStream(new File("d:/UnderTest/wavtester.wav")); Clip clip = AudioSystem.getClip(); clip.open(ais); clip.loop(-1); // keep playing the sound } catch(Exception exc) { System.out.println(exc); } } } 

此代码确实使输出声音线程工作 ,但不播放任何内容。 在这段代码中,我已经启动了一个单独的线程来播放声音,程序不应该终止,直到声音线程完成它的工作。但程序在打印一系列声音线程工作后终止。

这是什么原因(程序终止和声音没有播放)

问题是Clip已经启动了一个后台守护程序线程来播放wave文件。

因此,代码的执行流程如下:

  • 主线程启动辅助(无用)线程
  • 辅助线程启动守护程序线程(将播放声音)
  • 同时,主线程在辅助线程处于活动状态时继续打印
  • 当辅助线程完成启动回放线程时,它将结束,因此辅助线程将不再处于活动状态
  • 主线程将注意到辅助线程未处于活动状态并且也将结束
  • 由于回放线程是一个守护程序线程 ,JVM将退出(因为只剩下的线程是守护进程线程)

最后的结果正是你所看到的:一些文本由主线程打印,而辅助线程正在启​​动回放线程,当回放线程开始播放时,JVM结束。 有时你甚至可以在JVM退出之前从耳机中听到一些“点击”(当声音开始播放时)。

最简单的解决方法是在播放声音时使辅助线程(即非守护程序线程)hibernate。

 ... clip.open(ais); clip.loop(-1); Thread.sleep(amountToSleep); ... 

需要注意的一件重要事情是 :大约1年前,当我使用java API时,我注意到方法getMicrosecondLength()是错误的。 我在Windows和Linux上都编码,在一个平台上我得到了正确的值,但在另一个平台上,同样的方法会以毫秒为单位返回长度!

我发现获得声音实际长度的最可靠方法是使用getFrameLength()方法,并从中计算长度。

我找不到我在这个笔记本上写的代码。 我将在稍后的另一台PC上查看,如果我发现它,我将发布一个完整的示例(在带有SunJVM和Linux的Windows上使用OpenJDK或Sun可靠地运行)。

 import javax.sound.sampled.*; import java.io.*; import javax.swing.*; public class Tester { static Thread th; public static void main(String[] args) throws Exception { Clip clip = AudioSystem.getClip(); AudioInputStream ais = AudioSystem.getAudioInputStream(new File("d:/UnderTest/wavtester.wav")); clip.open(ais); clip.loop(0); // Calculate totalFrames long totalFrames = (long)(clip.getFrameLength() * clip.getFormat().getFrameRate()); Thread.sleep( ( totalFrames* 1000 )); // pause the thread till the sound plays System.out.println(clip.getFrameLength()); System.out.println(clip.getFormat().getFrameRate()); } } 
 while(clip.isRunning()){} 

更好