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

Suh*_*pta 3 java audio multithreading javasound

代码

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);
     }       
 }
}
Run Code Online (Sandbox Code Playgroud)

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

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

Bru*_*eis 6

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

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

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

最后的结果正是你所看到的:当辅助线程启动播放线程时,主线程会打印一些文本,当播放线程开始播放时,JVM就会完成.有时你甚至可以在JVM退出之前从耳机中听到一些"点击"(当声音开始播放时).

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

...
  clip.open(ais);
  clip.loop(-1);
  Thread.sleep(amountToSleep);
...
Run Code Online (Sandbox Code Playgroud)

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

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

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