2012-03-26 31 views
5

我有一個簡單的捕捉/回放Swing應用程序,它必須檢測是否沒有連接到計算機的適當麥克風並警告用戶。很多擺弄周圍後,我發現,讓我以檢測新連接或刪除話筒唯一的解決辦法:Java聲音刷新連接麥克風後的線路列表

 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解決方法?

UPDATE:拋出異常代碼:

 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. 
+0

有趣的問題,+1。只是爲了檢查,你確實意識到在'com.sun'包中使用類的脆弱性,對吧?即使在它存在的JRE中,它也可能在下一個版本中被刪除/移動/重命名。 – 2012-03-26 15:21:47

+0

的確,我確實意識到這至少是一種不好的做法,但它確實是我最後的手段。我認爲它可以被認爲是Java Sound的一個實現缺陷。 – 2012-03-26 15:25:24

+0

其中之一。 JavaSound對於它旨在支持的有限範圍內的事物很有好處,但Sun從未真正開發過它。 – 2012-03-26 15:29:52

回答

0

發佈拋出異常可能有助於代碼。

我假設你只使用Port.Info檢測麥克風,然後得到一個。數據線的存在記錄:

TargetDataLine dataLine = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, audioFormat));      
dataLine.open(); 
dataLine.start();    
dataLine.read(b, offset, len); 

注意斷開麥克風時,您可能還是會得到一個類似的例外如果麥克風在檢查存在的時間與嘗試獲取Dataline記錄的時間之間物理斷開連接,但連接微連接器不應成爲問題。

+0

看來我正在做幾乎相同的事情。無論如何,我已經用代碼和例外更新了問題。 – 2012-03-29 14:28:00

+0

確保線路支持該音頻格式。要列出該行支持的所有音頻格式: AudioFormat adfs [] =((DataLine.Info)dataLine.getLineInfo())。getFormats();對於(AudioFormat adf:adfs){ System.out.println(adf.toString()); } – msam 2012-03-30 07:07:13

+0

我不完全明白你的想法。 line =(TargetDataLine)AudioSystem。函數getline(INFO);是拋出異常的地方,所以我不能首先得到這條線。也許我還不夠清楚:如果麥克風在節目開始之前連接到計算機,則麥克風可以正常工作。正確檢測到斷開連接,「記錄」按鈕被禁用。當插回時它再次工作。如果麥克風在jvm啓動之前未連接,則會出現問題。在這種情況下,即使檢測到Port.Info.MICROPHONE,它的行仍然不起作用。 – 2012-03-30 12:17:12

0

使用原來的文章作爲靈感,我想出了這個作爲檢測麥克風何時丟失或獲得的手段。它檢測(在我的系統上)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; 
}