我有一个简单的捕获/播放Swing应用程序,它必须检测计算机上是否没有连接合适的麦克风并警告用户。经过一番折腾,我找到了唯一能让我检测到新连接或移除的麦克风的解决方案:
com.sun.media.sound.JDK13Services.setCachingPeriod(0);
private static boolean isMicrophoneAvailable() {
try {
if (!AudioSystem.isLineSupported(Port.Info.MICROPHONE)) {
log.debug("NO MICROPHONE FOUND");
return false;
} else {
log.debug("MICROPHONE FOUND");
return true;
}
} catch (IllegalArgumentException e) {
log.debug("INCONSISTENT");
}
return false;
}
在后台线程中调用如下:
new Thread() {
public void run() {
while(!thisFrame.isClosed()){
if(isMicrophoneAvailable() == true){
//OK
}else{
//WARN
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
问题是,尽管使用所描述的方法正确地检测到了设备,但基本线路的列表没有刷新。也就是说,当程序启动,并且稍后连接设备时,在尝试录制声音时会抛出以下异常:
java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.
有什么方法可以刷新AudioSystem的行列表吗?也许是类似于JDK13Services
的解决方法,它在一开始就用来避免缓存?
更新:引发异常的代码:
AudioFormat format = formatControls.getDefaultFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class,format);
try {
line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format, line.getBufferSize());
} catch (LineUnavailableException ex) {
shutDown("No audio input device available. Please make sure that a microphone is attached to your computer");
return;
} catch (Exception ex) {
log.error(ex.toString());
shutDown(ex.toString());
return;
}
以及异常本身:
java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, big-endian is supported.
以最初的帖子为灵感,我想出了这个方法来检测麦克风何时丢失或获得。它(在我的系统上)检测USB麦克风何时插入或拔出。我从后台线程循环调用它。最初的方法对我不起作用,因为笔记本电脑上有一个内置麦克风,所以我需要检测第二个麦克风的添加情况。
...
//call this once somewhere to turn the caching period down for faster detection
try
{
//try to set the caching period, defaults to something like 55 seconds
com.sun.media.sound.JDK13Services.setCachingPeriod(5);
}
catch( Exception e)
{
System.err.println("exception attempting to call com.sun.media.sound.JDK13Services.setCachingPeriod->" + e);
}
...
private int lastNumMics = -1;
private synchronized void micCheck()
{
Line.Info[] lineInfoArray = AudioSystem.getSourceLineInfo(Port.Info.MICROPHONE);
int numMics = lineInfoArray == null ? 0 : lineInfoArray.length;
if( lastNumMics > -1 )
{
if( numMics < lastNumMics )
{
//MICROPHONE_LOST
}
else if( numMics > lastNumMics )
{
//MICROPHONE_GAINED
}
}
lastNumMics = numMics;
}
发布引发异常的代码可能会有所帮助。
我假设你只使用端口信息来检测麦克风的存在,然后让数据线记录:
TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, audioFormat));
dataLine.open();
dataLine.start();
dataLine.read(b, offset, len);
请注意,如果在检查是否存在麦克风和尝试录制数据线之间麦克风已物理断开连接,则在断开麦克风连接时仍可能出现类似的异常,但连接microhpone应该不会有问题。