检查调音台线路中的音频播放级别?
我试图弄清楚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构建一个包装器并使用它来正确实现这些方法。 希望这会有所帮助。
- Android Tab Fragment(Eclipse ApI 22)中不推荐使用ActionBarActivity和ActionBar.TabListener
- 有没有办法在Android的软键盘上首先显示数字?
- 在ArrayList的开头添加元素的时间复杂度是多少?
- 如何在sqlite数据库中插入数据类型日期(yyyy-MM-dd)并在android中的两个日期之间检索数据
- ZXing Result.getRawBytes(),究竟是什么?
- 从列表中查找最近的日期
- Java:从图像中裁剪出具有特定颜色的区域
- 想要使用GoogleMaps – OnMyLocationChangeListener却无法实现吗? 任何其他选择
- 在Java中定义了类型后,同时初始化多个变量?