2011-07-29 50 views
3

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

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); 
    }  
} 
} 

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

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

+0

我的意思编辑[* *其他问题(http://stackoverflow.com/questions/6863384/understanding-the-constructor-of-audioformat-audioinputstream -and - 开始 - 方法/)。但是我在那里发表的同样的评论在这里适用。链接源代码中的最后两条单行注释对您意味着什么? –

+0

@ Andrew Thompson这意味着程序只有在由'clip'生成的守护线程完成后才会终止。但是我不知道为什么它在3-4秒之后完成。 –

+0

@ Andrew Thompson'JOptionPane'出现一段时间后自行消失。我之前发布了这个问题,但没有得到任何有意义的答案http://stackoverflow.com/questions/6594921/how-does-boolean-here-become-false-on-its-own –

回答

6

的问题是,Clip已经启动后台守护线程播放波形文件。

所以,你的代码的执行流程如下:

  • 主线程启动二级(没用)螺纹
  • 辅助线程启动一个守护线程(将播放的声音)
  • 在此期间,主线程不断打印的东西,而辅助线程是活着
  • 当辅助线程完成推出播放线程,它就会结束,所以辅助线程的Wi会不处于活动状态再
  • 主线程会注意到辅助线程是不活动的,将结束以及
  • 由于重放线程是守护线程,JVM将退出(因为只有左线程是守护线程)

最终的结果正是你所看到的:一些文本得到由主线程同时,打印辅助线程正在启​​动播放线程,当播放线程将开始播放,咚, JVM完成。在JVM退出之前,有时甚至可能会听到某些“点击”(如声音开始播放)。

最简单的修复方法是在播放声音时使辅助线程(即非守护进程线程)处于睡眠状态。注意

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

一件重要的事情:大约一年前,当我与Java API的工作,我注意到,该方法getMicrosecondLength()是马车。我在Windows和Linux中都编码,并且在一个平台上我会得到正确的值,但在另一个平台上,同样的方法会返回毫秒数的长度!

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

我找不到当时在本笔记本上写的代码。我将在另一台PC上稍后检查,如果我找到它,我会发布一个完整的示例(在Windows上使用Sun JVM和Linux与OpenJDK或Sun可靠地工作)。

+0

我得到帧的长度'504845'我怎么知道它的轨道长度? –

+0

这是我不记得确切......我必须检查我的代码以确保。但是你可以尝试像'clip.getFormat()。getFrameRate()'这样的应用程序,它可以在每秒钟给出帧的数量(通常这个值在8000到44100之间)。然后,将帧数(getFrameLength())除以帧速率,并以秒为单位获取片段的长度。 –

0
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());   
} 
} 
+0

我想删除'try {} catch {}'块并只保留'Thread.sleep(...)',因为在这样一个简单的代码中你不需要(你甚至已经声明了'main'方法作为'throws Exception'),并且在生产代码中,这远远不是处理'InterruptedException'的正确方法。 –

+0

@ Bruno Reis编辑代码 –

0
while(clip.isRunning()){} 

更好

+1

如果我已经通过'clip.stop()停止/暂停了该行,并且主线程完成了工作,该怎么办?它会返回'true',我会被抛出程序。我认为这种检查不适合这种情况。 –