2014-03-01 74 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的包裝,並用它來正確地實現這些方法。希望這有助於。