2011-05-14 11 views
14

Tengo un problema relacionado con mi pregunta anterior. Quiero grabar audio desde el mezclador (altavoces), estoy usando javax.sound. Tengo que configurar audioFormat y no sé qué escribir allí:/Utilizando la clase ListMixer (que encontré aquí ->http://forums.oracle.com/forums/thread.jspa?threadID=2198477&tstart=2), escribo algo como esto: http://forums.oracle.com/forums/thread.jspa?threadID=2198477&tstart=2 pero no tengo ninguna información sobre la frecuencia de muestreo (tasa de muestreo desconocida). Programa está lanzando esta excepción:Java: grabación desde el mezclador

java.lang.IllegalArgumentException: línea incompatible: Interfaz TargetDataLine compatible con el formato PCM_UNSIGNED 44100,0 Hz, 8 bits, mono, 4 bytes/marco,

Código:

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

donde poder encontrar una solución? –

Respuesta

9

Obtendrá una TargetDataLine utilizando un AudioFormat que ha creado. Esto no está garantizado para funcionar. Primero debe consultar el Mezclador para verificar si es compatible con el formato de audio que desee utilizando el método AudioSystem.isLineSupported(Info info).

Personalmente, esto me parece bastante engorroso. Debe consultar los Mezcladores en el sistema para determinar si son compatibles con el AudioFormato que desea.

La siguiente función obtendrá un Vector de formatos admitidos para una clase de línea de datos. Llamarlo usando

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

o

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

Este código puede ser que necesite un poco de depuración; Tuve que quitar algunas de mis cosas específicas de la aplicación para que sea autónomo ...

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

Algo está mal:/No he podido hacer coincidir el AudioFormat con el mezclador, así que modifiqué tu función por lo que solo compruebo primero el mezclador (general). La función encuentra 3 formatos de audio pero aún no funciona: / –

7

Es posible obtener todas ellas asistidas Lines y su AudioFormats directamente. Lo hice para el SourceDataLines del predeterminado Mixer en el sistema, y ​​usted puede editar fácilmente el código para obtener cualquier tipo de Lines y AudioFormats compatible con cualquier Mixer.

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(); 

puedo obtener una salida como esta:

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 
Cuestiones relacionadas