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

Posted

技术标签:

【中文标题】为啥这段代码不播放声音文件【英文标题】:why this code doesn't play the sound file为什么这段代码不播放声音文件 【发布时间】:2011-07-29 08:55:55 【问题描述】:

代码

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

这段代码确实提供了输出 sound thread working ,但不播放任何东西。在这段代码中,我已经启动了一个单独的线程来播放声音,并且在声音线程完成它的工作之前程序不应该终止。但是程序在打印一系列声音线程工作后终止。

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

【问题讨论】:

我的意思是编辑你的other question。但是我在那里制作的相同 cmets 在这里适用。链接源中的最后两个单行 cmets 对您意味着什么? @Andrew Thompson 这意味着程序只有在由clip 生成的守护线程完成后才会终止。但我不知道为什么它会在播放 3-4 秒后结束。 @ Andrew Thompson JOptionPane 出现一段时间后自行消失。我之前发布过这个问题,但没有得到任何有意义的答案***.com/questions/6594921/… "JOptionPane 出现一段时间后自行消失。" 我能想到的唯一一件事就是“您的 Java 安装已损坏”。 @Andrew Thompson 你说的坏了是什么意思 【参考方案1】:

问题是Clip 已经启动了一个后台daemon线程来播放波形文件。

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

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

最终结果正是您所看到的:当辅助线程启动播放线程时,主线程打印了一些文本,当播放线程开始播放时,轰隆隆,JVM 结束。有时您甚至可以在 JVM 退出之前从耳机中听到一些“咔哒”声(当声音开始播放时)。

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

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

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

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

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

【讨论】:

我得到了504845的帧长度我怎么知道它的轨道长度? 这是我不记得的确切内容...我必须检查我的代码才能确定。但是您可以尝试clip.getFormat().getFrameRate() 之类的方法,它应该为您提供每秒的帧数(通常这个值在 8000 到 44100 之间)。然后将帧数 (getFrameLength()) 除以帧速率,得到剪辑的长度(以秒为单位)。【参考方案2】:
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());           
 

【讨论】:

我会删除try catch 块并只留下Thread.sleep(...),因为在这样一个简单的代码中没有必要(您甚至将main 方法声明为throws Exception) ,而在生产代码中,这与处理InterruptedException 的正确方法相去甚远。【参考方案3】:
while(clip.isRunning()) 

更好

【讨论】:

如果我通过clip.stop() 停止/暂停了该行并且主线程完成了它的工作,该怎么办。它将返回true,我将被排除在程序之外。我认为这张支票不符合条件。

以上是关于为啥这段代码不播放声音文件的主要内容,如果未能解决你的问题,请参考以下文章

为啥 xcode 播放声音文件时没有任何资源路径?

为啥播放视频文件只有声音没有图像

为啥是 MediaElement 不播放任何声音的原因

为啥 PyGame 不播放声音

AVPlayer 不播放 URL 声音 Swift 3

为啥不播放声音?