2011-05-14 41 views
14

我有一個問題與我以前的問題有關。我想從混音器(揚聲器)錄製音頻,我正在使用javax.sound。我必須設置audioFormat,我不知道該鍵入什麼:/使用類ListMixer(我在這裏找到 - >http://forums.oracle.com/forums/thread.jspa?threadID=2198477&tstart=2),我寫這樣的:http://forums.oracle.com/forums/thread.jspa?threadID=2198477&tstart=2,但我沒有關於採樣率的任何信息(未知採樣率)。程序被投擲此異常:Java - 從調音臺錄音

java.lang.IllegalArgumentException異常:行不支持:接口TargetDataLine的支持格式PCM_UNSIGNED 44100.0赫茲,8位,單聲道,4個字節/幀,

代碼:

package sound; 

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import javax.sound.sampled.*; 

public class AudioCapture02 extends JFrame{ 

    boolean stopCapture = false; 
    ByteArrayOutputStream byteArrayOutputStream; 
    AudioFormat audioFormat; 
    TargetDataLine targetDataLine; 
    AudioInputStream audioInputStream; 
    SourceDataLine sourceDataLine; 

    public AudioCapture02(){//constructor 
    final JButton captureBtn = 
          new JButton("Capture"); 
    final JButton stopBtn = new JButton("Stop"); 
    final JButton playBtn = 
         new JButton("Playback"); 

    captureBtn.setEnabled(true); 
    stopBtn.setEnabled(false); 
    playBtn.setEnabled(false); 

    //Register anonymous listeners 
    captureBtn.addActionListener(
     new ActionListener(){ 
     public void actionPerformed(
           ActionEvent e){ 
      captureBtn.setEnabled(false); 
      stopBtn.setEnabled(true); 
      playBtn.setEnabled(false); 
      //Capture input data from the 
      // microphone until the Stop button is 
      // clicked. 
      captureAudio(); 
     }//end actionPerformed 
     }//end ActionListener 
    );//end addActionListener() 
    getContentPane().add(captureBtn); 

    stopBtn.addActionListener(
     new ActionListener(){ 
     public void actionPerformed(
           ActionEvent e){ 
      captureBtn.setEnabled(true); 
      stopBtn.setEnabled(false); 
      playBtn.setEnabled(true); 
      //Terminate the capturing of input data 
      // from the microphone. 
      stopCapture = true; 
     }//end actionPerformed 
     }//end ActionListener 
    );//end addActionListener() 
    getContentPane().add(stopBtn); 

    playBtn.addActionListener(
     new ActionListener(){ 
     public void actionPerformed(
           ActionEvent e){ 
      //Play back all of the data that was 
      // saved during capture. 
      playAudio(); 
     }//end actionPerformed 
     }//end ActionListener 
    );//end addActionListener() 
    getContentPane().add(playBtn); 

    getContentPane().setLayout(new FlowLayout()); 
    setTitle("Capture/Playback Demo"); 
    setDefaultCloseOperation(EXIT_ON_CLOSE); 
    setSize(250,70); 
    setVisible(true); 
    }//end constructor 

    //This method captures audio input from a 
    // microphone and saves it in a 
    // ByteArrayOutputStream object. 
    private void captureAudio(){ 
    try{ 
     //Get and display a list of 
     // available mixers. 
     Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); 
     System.out.println("Available mixers:"); 
     for(int cnt = 0; cnt < mixerInfo.length; 
              cnt++){ 
     System.out.println(mixerInfo[cnt]. 
             getName()); 
     }//end for loop 

     //Get everything set up for capture 
     audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, 44100.0F, 8, 1, 4, 44100.0F, 
         false); 


     DataLine.Info dataLineInfo = 
          new DataLine.Info(
          TargetDataLine.class, 
          audioFormat); 
     ListMixers lm = new ListMixers(); 
     lm.listAll(new PrintWriter(System.out)); 

     System.out.println(" AKTUALNY => "+mixerInfo[0].getName()); 
     Mixer mixer = AudioSystem.getMixer(mixerInfo[0]); 

     //Get a TargetDataLine on the selected 
     // mixer. 
     targetDataLine = (TargetDataLine) 
        mixer.getLine(dataLineInfo); 
     //Prepare the line for use. 
     targetDataLine.open(audioFormat); 
     targetDataLine.start(); 

     //Create a thread to capture the microphone 
     // data and start it running. It will run 
     // until the Stop button is clicked. 
     Thread captureThread = new CaptureThread(); 
     captureThread.start(); 
    } catch (Exception e) { 
     System.out.println(e); 
     System.exit(0); 
    }//end catch 
    }//end captureAudio method 

    //This method plays back the audio data that 
    // has been saved in the ByteArrayOutputStream 
    private void playAudio() { 
    try{ 
     //Get everything set up for playback. 
     //Get the previously-saved data into a byte 
     // array object. 
     byte audioData[] = byteArrayOutputStream. 
            toByteArray(); 
     //Get an input stream on the byte array 
     // containing the data 
     InputStream byteArrayInputStream = 
      new ByteArrayInputStream(audioData); 
     AudioFormat audioFormat = getAudioFormat(); 
     audioInputStream = new AudioInputStream(
        byteArrayInputStream, 
        audioFormat, 
        audioData.length/audioFormat. 
           getFrameSize()); 
     DataLine.Info dataLineInfo = 
          new DataLine.Info(
          SourceDataLine.class, 
          audioFormat); 
     sourceDataLine = (SourceDataLine) 
       AudioSystem.getLine(dataLineInfo); 
     sourceDataLine.open(audioFormat); 
     sourceDataLine.start(); 

     //Create a thread to play back the data and 
     // start it running. It will run until 
     // all the data has been played back. 
     Thread playThread = new PlayThread(); 
     playThread.start(); 
    } catch (Exception e) { 
     System.out.println(e); 
     System.exit(0); 
    }//end catch 
    }//end playAudio 

    //This method creates and returns an 
    // AudioFormat object for a given set of format 
    // parameters. If these parameters don't work 
    // well for you, try some of the other 
    // allowable parameter values, which are shown 
    // in comments following the declartions. 
    private AudioFormat getAudioFormat(){ 
    float sampleRate = 8000.0F; 
    //8000,11025,16000,22050,44100 
    int sampleSizeInBits = 16; 
    //8,16 
    int channels = 1; 
    //1,2 
    boolean signed = true; 
    //true,false 
    boolean bigEndian = false; 
    //true,false 
    return new AudioFormat(
         sampleRate, 
         sampleSizeInBits, 
         channels, 
         signed, 
         bigEndian); 
    }//end getAudioFormat 
//=============================================// 

//Inner class to capture data from microphone 
class CaptureThread extends Thread{ 
    //An arbitrary-size temporary holding buffer 
    byte tempBuffer[] = new byte[10000]; 
    public void run(){ 
    byteArrayOutputStream = 
        new ByteArrayOutputStream(); 
    stopCapture = false; 
    try{//Loop until stopCapture is set by 
     // another thread that services the Stop 
     // button. 
     while(!stopCapture){ 
     //Read data from the internal buffer of 
     // the data line. 
     int cnt = targetDataLine.read(tempBuffer, 
           0, 
           tempBuffer.length); 
     if(cnt > 0){ 
      //Save data in output stream object. 
      byteArrayOutputStream.write(tempBuffer, 
             0, 
             cnt); 
     }//end if 
     }//end while 
     byteArrayOutputStream.close(); 
    }catch (Exception e) { 
     System.out.println(e); 
     System.exit(0); 
    }//end catch 
    }//end run 
}//end inner class CaptureThread 
//===================================// 
//Inner class to play back the data 
// that was saved. 
class PlayThread extends Thread{ 
    byte tempBuffer[] = new byte[10000]; 

    public void run(){ 
    try{ 
     int cnt; 
     //Keep looping until the input read method 
     // returns -1 for empty stream. 
     while((cnt = audioInputStream.read(
         tempBuffer, 0, 
         tempBuffer.length)) != -1){ 
     if(cnt > 0){ 
      //Write data to the internal buffer of 
      // the data line where it will be 
      // delivered to the speaker. 
      sourceDataLine.write(tempBuffer,0,cnt); 
     }//end if 
     }//end while 
     //Block and wait for internal buffer of the 
     // data line to empty. 
     sourceDataLine.drain(); 
     sourceDataLine.close(); 
    }catch (Exception e) { 
     System.out.println(e); 
     System.exit(0); 
    }//end catch 
    }//end run 
}//end inner class PlayThread 
//=============================================// 
class ListMixers { 
    PrintWriter out; 

    void listAll(final PrintWriter out) { 
     this.out = out; 
     Mixer.Info[] aInfos = AudioSystem.getMixerInfo(); 
     for (int i = 0; i < aInfos.length; i++) { 
      try { 
       Mixer mixer = AudioSystem.getMixer(aInfos[i]); 
       out.println(""+i+": "+aInfos[i].getName()+", " 
         +aInfos[i].getVendor()+", " 
         +aInfos[i].getVersion()+", " 
         +aInfos[i].getDescription()); 

       printLines(mixer, mixer.getSourceLineInfo()); 
       printLines(mixer, mixer.getTargetLineInfo()); 
      } catch (Exception e) { 
       out.println("Exception: "+e); 
      } 
      out.println(); 
     } 
     if (aInfos.length == 0) { 
      out.println("[No mixers available]"); 
     } 
    } 

    void printLines(Mixer mixer, Line.Info[] infos) { 
     for (int i = 0; i < infos.length; i++) { 
      try { 
       if (infos[i] instanceof Port.Info) { 
        Port.Info info = (Port.Info) infos[i]; 

        out.println(" Port " + info); 
       } 
       if (infos[i] instanceof DataLine.Info) { 
        DataLine.Info info = (DataLine.Info) infos[i]; 

        out.println(" Line " + info + " (max. " + 
           mixer.getMaxLines(info) + " simultaneously): "); 
        printFormats(info); 
       } 
       Line line = mixer.getLine(infos[i]); 

       if (!(line instanceof Clip)) { 
        try { 
         line.open(); 
        } 
        catch (LineUnavailableException e) { 
         out.println("LineUnavailableException when trying to open this line"); 
        } 
       } 
       try { 
        printControls(line.getControls()); 
       } 
       finally { 
        if (!(line instanceof Clip)) { 
         line.close(); 
        } 
       } 
      } 
      catch (Exception e) { 
       out.println("Exception: " + e); 
      } 
      out.println(); 
     } 
    } 

    void printFormats(DataLine.Info info) { 
     AudioFormat[] formats = info.getFormats(); 
     for (int i = 0; i < formats.length; i++) { 
      out.println(" "+i+": "+formats[i] 
        +" ("+formats[i].getChannels()+" channels, " 
        +"frameSize="+formats[i].getFrameSize()+", " 
        +(formats[i].isBigEndian()?"big endian":"little endian") 
        +")"); 
     } 
     if (formats.length == 0) { 
      out.println(" [no formats]"); 
     } 
     out.println(); 
    } 

    void printControls(Control[] controls) { 
     for (int i = 0; i<controls.length; i++) { 
      printControl(" ", "Controls["+i+"]: ", controls[i]); 
     } 
     if (controls.length == 0) { 
      out.println(" [no controls]"); 
     } 
     out.println(); 
    } 

    void printControl(String indent, String id, Control control) { 
     if (control instanceof BooleanControl) { 
      BooleanControl ctrl = (BooleanControl) control; 
      out.println(indent+id+"BooleanControl: "+ctrl); 
     } else if (control instanceof CompoundControl) { 
      CompoundControl ctrl = (CompoundControl) control; 
      Control[] ctrls = ctrl.getMemberControls(); 
      out.println(indent+id+"CompoundControl: "+control); 
      for (int i=0; i<ctrls.length; i++) { 
       printControl(indent+" ", "MemberControls["+i+"]: ", ctrls[i]); 
      } 
     } else if (control instanceof EnumControl) { 
      EnumControl ctrl = (EnumControl) control; 
      Object[] values = ctrl.getValues(); 
      Object value = ctrl.getValue(); 
      out.println(indent+id+"EnumControl: "+control); 
      for (int i=0; i<values.length; i++) { 
       if (values[i] instanceof Control) { 
        printControl(indent+" ", "Values["+i+"]: "+((values[i]==value)?"*":""), (Control) values[i]); 
       } else { 
        out.println(indent+" Values["+i+"]: "+((values[i]==value)?"*":"")+values[i]); 
       } 
      } 
     } else if (control instanceof FloatControl) { 
      FloatControl ctrl = (FloatControl) control; 
      out.println(indent+id+"FloatControl: "+ctrl); 
     } else { 
      out.println(indent+id+"Control: "+control); 
     } 
    } 
} 
}//end outer class AudioCapture02.java 
+3

在這裏你能找到一個解決辦法? – 2014-01-24 17:58:45

回答

9

您正在使用您創建的AudioFormat獲取TargetDataLine。這不能保證工作。您必須先使用AudioSystem.isLineSupported(Info info)方法查詢混音器以檢查它是否支持您所需的AudioFormat。

就我個人而言,我覺得這很麻煩。您需要查詢系統上的混音器以確定它們是否支持所需的AudioFormat。

下面的函數將獲得數據線類的支持格式的向量。使用

Vector<AudioFormat> formats = getSupportedFormats(TargetDataLine.class); 

Vector<AudioFormat> formats = getSupportedFormats(SourceDataLine.class); 

該代碼可能需要一些調試的調用它;我不得不刪除我的一些應用程序特定的東西,使其自給自足的...

public Vector<AudioFormat> getSupportedFormats(Class<?> dataLineClass) { 
    /* 
    * These define our criteria when searching for formats supported 
    * by Mixers on the system. 
    */ 
    float sampleRates[] = { (float) 8000.0, (float) 16000.0, (float) 44100.0 }; 
    int channels[] = { 1, 2 }; 
    int bytesPerSample[] = { 2 }; 

    AudioFormat format; 
    DataLine.Info lineInfo; 

    SystemAudioProfile profile = new SystemAudioProfile(); // Used for allocating MixerDetails below. 
    Vector<AudioFormat> formats = new Vector<AudioFormat>(); 

    for (Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) { 
     for (int a = 0; a < sampleRates.length; a++) { 
      for (int b = 0; b < channels.length; b++) { 
       for (int c = 0; c < bytesPerSample.length; c++) { 
        format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 
          sampleRates[a], 8 * bytesPerSample[c], channels[b], bytesPerSample[c], 
          sampleRates[a], false); 
        lineInfo = new DataLine.Info(dataLineClass, format); 
        if (AudioSystem.isLineSupported(lineInfo)) { 
         /* 
         * TODO: To perform an exhaustive search on supported lines, we should open 
         * TODO: each Mixer and get the supported lines. Do this if this approach 
         * TODO: doesn't give decent results. For the moment, we just work with whatever 
         * TODO: the unopened mixers tell us. 
         */ 
         if (AudioSystem.getMixer(mixerInfo).isLineSupported(lineInfo)) { 
          formats.add(format); 
         } 
        } 
       } 
      } 
     } 
    } 
    return formats; 
} 
+0

的東西是錯誤的:/我不是能夠配合調音臺的AudioFormat所以我修改你的功能,所以其只檢查首先找到混頻器(一般)。功能找到3種音頻格式,但它仍然不起作用:/ – 2011-05-14 17:29:20

7

有可能獲得所有直接支持Lines及其AudioFormats。我這樣做是爲系統默認MixerSourceDataLines,你可以輕鬆地編輯代碼即可獲得任何Mixer支持的任何類型的LinesAudioFormats

Mixer mixer = AudioSystem.getMixer(null); // default mixer 
mixer.open(); 

System.out.printf("Supported SourceDataLines of default mixer (%s):\n\n", mixer.getMixerInfo().getName()); 
for(Line.Info info : mixer.getSourceLineInfo()) { 
    if(SourceDataLine.class.isAssignableFrom(info.getLineClass())) { 
     SourceDataLine.Info info2 = (SourceDataLine.Info) info; 
     System.out.println(info2); 
     System.out.printf(" max buffer size: \t%d\n", info2.getMaxBufferSize()); 
     System.out.printf(" min buffer size: \t%d\n", info2.getMinBufferSize()); 
     AudioFormat[] formats = info2.getFormats(); 
     System.out.println(" Supported Audio formats: "); 
     for(AudioFormat format : formats) { 
      System.out.println(" "+format); 
//   System.out.printf("  encoding:   %s\n", format.getEncoding()); 
//   System.out.printf("  channels:   %d\n", format.getChannels()); 
//   System.out.printf(format.getFrameRate()==-1?"":"  frame rate [1/s]: %s\n", format.getFrameRate()); 
//   System.out.printf("  frame size [bytes]: %d\n", format.getFrameSize()); 
//   System.out.printf(format.getSampleRate()==-1?"":"  sample rate [1/s]: %s\n", format.getSampleRate()); 
//   System.out.printf("  sample size [bit]: %d\n", format.getSampleSizeInBits()); 
//   System.out.printf("  big endian:   %b\n", format.isBigEndian()); 
//   
//   Map<String,Object> prop = format.properties(); 
//   if(!prop.isEmpty()) { 
//    System.out.println("  Properties: "); 
//    for(Map.Entry<String, Object> entry : prop.entrySet()) { 
//     System.out.printf("  %s: \t%s\n", entry.getKey(), entry.getValue()); 
//    } 
//   } 
     } 
     System.out.println(); 
    } else { 
     System.out.println(info.toString()); 
    } 
    System.out.println(); 
} 

mixer.close(); 

我得到這樣的輸出:

interface SourceDataLine supporting 8 audio formats, and buffers of at least 32 bytes 
    max buffer size: -1 
    min buffer size: 32 
    Supported Audio formats: 
    PCM_UNSIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame, 
    PCM_SIGNED unknown sample rate, 8 bit, mono, 1 bytes/frame, 
    PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, little-endian 
    PCM_SIGNED unknown sample rate, 16 bit, mono, 2 bytes/frame, big-endian 
    PCM_UNSIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame, 
    PCM_SIGNED unknown sample rate, 8 bit, stereo, 2 bytes/frame, 
    PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, little-endian 
    PCM_SIGNED unknown sample rate, 16 bit, stereo, 4 bytes/frame, big-endian 


interface Clip supporting 8 audio formats, and buffers of at least 32 bytes