2014-03-01 43 views
6

我想弄清楚是否有任何声音在Windows中播放(通过任何应用程序)。如果有什么地方发出噪音,我想知道它!检查混音器线中音频播放的级别?

下面的文档后,我已经找到了如何获得机器上的混音器列表,以及这些混音器的线路 - 如果我理解正确,是什么用于输入/输出混合器。

但是,我遇到的问题是,我不知道如何从行中获取所需的数据。

我看到的唯一具有音量级别概念的接口是DataLine。问题在于我无法弄清楚返回实现数据接口的对象。

枚举所有的混频器和行:

public static void printMixers() { 
    Mixer.Info[] mixers = AudioSystem.getMixerInfo(); 
    for (Mixer.Info mixerInfo : mixers) { 
     Mixer mixer = AudioSystem.getMixer(mixerInfo); 
     try { 
      mixer.open(); 
      Line.Info[] lines = mixer.getSourceLineInfo(); 
      for (Line.Info linfo : lines) { 
       System.out.println(linfo); 
      } 
     } 
     catch (LineUnavailableException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

该代码枚举并显示所有我的机器上的音频设备。那么,Lines中不应该包含某种回放级别的数据吗?

+0

考虑添加一个Audio或Javasound标记来提醒用户这个特别的兴趣! –

回答

6

哦,你想找到音量?那么,并不是所有的硬件都支持它,但这里是你如何获得数据。

public static SourceDataLine getSourceDataLine(Line.Info lineInfo){ 
    try{ 
     return (SourceDataLine) AudioSystem.getLine(lineInfo); 
    } 
    catch(Exception ex){ 
     ex.printStackTrace(); 
     return null; 
    } 
} 

然后只需调用SourceDataLine.getLevel()即可获取该卷。我希望这有帮助。

注意:如果声音是从JVM之外发出的,或者不是通过JavaSound API发出的,则此方法不会检测到声音,因为JVM无法访问与SourceDataLine等效的操作系统。

更新:进一步研究后,大多数系统上都没有实现getLevel()。所以我手动实现基于该方法从论坛讨论:https://community.oracle.com/message/5391003

这里是类:

public class Main { 

    public static void main(String[] args){ 
     MicrophoneAnalyzer mic = new MicrophoneAnalyzer(FLACFileWriter.FLAC); 
     System.out.println("HELLO"); 
     mic.open(); 
     while(true){ 
      byte[] buffer = new byte[mic.getTargetDataLine().getFormat().getFrameSize()]; 
      mic.getTargetDataLine().read(buffer, 0, buffer.length); 
      try{ 
       System.out.println(getLevel(mic.getAudioFormat(), buffer)); 
      } 
      catch(Exception e){ 
       System.out.println("ERROR"); 
       e.printStackTrace(); 
      } 
     } 
    } 

    public static double getLevel(AudioFormat af, byte[] chunk) throws IOException{ 
     PCMSigned8Bit converter = new PCMSigned8Bit(af); 
     if(chunk.length != converter.getRequiredChunkByteSize()) 
      return -1; 

     AudioInputStream ais = converter.convert(chunk); 
     ais.read(chunk, 0, chunk.length); 

     long lSum = 0; 
     for(int i=0; i<chunk.length; i++) 
      lSum = lSum + chunk[i]; 

     double dAvg = lSum/chunk.length; 
     double sumMeanSquare = 0d; 

     for(int j=0; j<chunk.length; j++) 

      sumMeanSquare = sumMeanSquare + Math.pow(chunk[j] - dAvg, 2d); 

     double averageMeanSquare = sumMeanSquare/chunk.length; 

     return (Math.pow(averageMeanSquare,0.5d)); 
    } 
} 

我使用的方法仅适用于8bitPCM所以我们的编码转换,使用这两个来类。这是一般的抽象转换器类。

import java.io.ByteArrayInputStream; 
import java.io.IOException; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 

abstract class AbstractSignedLevelConverter 
{ 
    private AudioFormat srcf; 

    public AbstractSignedLevelConverter(AudioFormat sourceFormat) 
    { 
     srcf = sourceFormat; 
    } 


    protected AudioInputStream convert(byte[] chunk) 
    { 
     AudioInputStream ais = null; 
     if(AudioSystem.isConversionSupported( AudioFormat.Encoding.PCM_SIGNED, 
                  srcf)) 
     { 
      if(srcf.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) 
       ais = AudioSystem.getAudioInputStream(
         AudioFormat.Encoding.PCM_SIGNED, 
         new AudioInputStream(new ByteArrayInputStream(chunk), 
                srcf, 
                chunk.length * srcf.getFrameSize())); 
      else 
       ais = new AudioInputStream(new ByteArrayInputStream(chunk), 
                srcf, 
                chunk.length * srcf.getFrameSize()); 
     } 

     return ais; 
    } 

    abstract public double convertToLevel(byte[] chunk) throws IOException; 

    public int getRequiredChunkByteSize() 
    { 
     return srcf.getFrameSize(); 
    } 
} 

这里是一个8BitPCM

import java.io.IOException; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 

public class PCMSigned8Bit extends AbstractSignedLevelConverter 
{ 
    PCMSigned8Bit(AudioFormat sourceFormat) 
    { 
     super(sourceFormat); 
    } 

    public double convertToLevel(byte[] chunk) throws IOException 
    { 
     if(chunk.length != getRequiredChunkByteSize()) 
      return -1; 

     AudioInputStream ais = convert(chunk); 
     ais.read(chunk, 0, chunk.length); 

     return (double)chunk[0]; 
    } 




} 

这是TargetDataLine的可能不是你使用的情况下工作,但你可以建立一个围绕的SourceDataLine的包装,并用它来正确地实现这些方法。希望这有助于。