检查调音台线路中的音频播放级别?

我试图弄清楚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不应该包含某种回放级数据吗?

哦,你想找到音量? 好吧,并非所有硬件都支持它,但这里是你获得数据线的方式。

  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 

我使用的方法只适用于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构建一个包装器并使用它来正确实现这些方法。 希望这会有所帮助。