This discussion is archived
4 Replies Latest reply: Mar 30, 2011 12:19 PM by captfoss RSS

Recording from LINE-IN problem

850977 Newbie
Currently Being Moderated
Hi at all,
I have a problem with recording input audio coming from LINE-IN of my pc.
I looked up on google and on this forum to find something useful but I found nothing. If I try to access line-in I get exception: Line unsupported.

I found a discovery code to find what I have on my pc:
.....
....
ArrayList<Mixer.Info> mixerInfos = new ArrayList<Mixer.Info>(Arrays.asList(AudioSystem.getMixerInfo()));
Line.Info portInfo = new Line.Info(Port.class);
for (Mixer.Info mixerInfo: mixerInfos) {
     Mixer mixer = AudioSystem.getMixer(mixerInfo);
     if (mixer.isLineSupported(portInfo)) {
          // found a Port Mixer
          System.out.println("Found mixer: " + mixerInfo.getName());
          System.out.println("\t" + mixerInfo.getDescription());
          System.out.println("Source Line Supported:");
          ArrayList<Line.Info> srcInfos = new ArrayList<Line.Info>(Arrays.asList(mixer.getSourceLineInfo()));
          for (Line.Info srcInfo: srcInfos) {
               Port.Info pi = (Port.Info) srcInfo;
               System.out.println("\t" + pi.getName() + ", " + (pi.isSource() ? "source" : "target"));
               showControls(mixer.getLine(srcInfo));
          } // of for Line.Info
          System.out.println("Target Line Supported:");
          ArrayList<Line.Info> targetInfos = new ArrayList<Line.Info> (Arrays.asList(mixer.getTargetLineInfo()));
          for (Line.Info targetInfo: targetInfos) {
               Port.Info pi = (Port.Info) targetInfo;
               System.out.println("\t" + pi.getName() + ", " + (pi.isSource() ? "source" : "target"));
               showControls(mixer.getLine(targetInfo));
          }
     } // of if
}
....
...
..follow the result:
Found mixer: Port Intel [hw:0]
    HDA Intel, Realtek ALC662 rev1
Source Line Supported:
     Front Mic Boost, source
          Available controls:
               Front Mic Boost Control containing Volume, and Balance Controls.
                    Volume with current value: 0.6666667  (range: 0.0 - 1.0)
                    Balance with current value: -2.9802322E-8  (range: -1.0 - 1.0)
     Mic Boost, source
          Available controls:
               Mic Boost Control containing Volume, and Balance Controls.
                    Volume with current value: 0.6666667  (range: 0.0 - 1.0)
                    Balance with current value: -2.9802322E-8  (range: -1.0 - 1.0)
     Capture, source
          Available controls:
               Capture Control containing Volume, Balance, and Select Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
                    Select Control with current value: true
     Capture, source
          Available controls:
               Capture Control containing Volume, Balance, and Select Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
                    Select Control with current value: true
Target Line Supported:
     Master, target
          Available controls:
               Master Control containing Volume, and Mute Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Mute Control with current value: false
     Headphone, target
          Available controls:
               Headphone Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
                    Mute Control with current value: false
     PCM, target
          Available controls:
               PCM Control containing Volume, and Balance Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
     Front, target
          Available controls:
               Front Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 1.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
                    Mute Control with current value: false
     Front Mic, target
          Available controls:
               Front Mic Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 0.61290324  (range: 0.0 - 1.0)
                    Balance with current value: -1.8822519E-8  (range: -1.0 - 1.0)
                    Mute Control with current value: true
     Front Mic Boost, target
          Available controls:
               Front Mic Boost Control containing Volume, and Balance Controls.
                    Volume with current value: 0.6666667  (range: 0.0 - 1.0)
                    Balance with current value: -2.9802322E-8  (range: -1.0 - 1.0)
     Line, target
          Available controls:
               Line Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 0.7096774  (range: 0.0 - 1.0)
                    Balance with current value: 2.9802322E-8  (range: -1.0 - 1.0)
                    Mute Control with current value: false
     Mic, target
          Available controls:
               Mic Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 0.7419355  (range: 0.0 - 1.0)
                    Balance with current value: -1.0366025E-8  (range: -1.0 - 1.0)
                    Mute Control with current value: true
     Mic Boost, target
          Available controls:
               Mic Boost Control containing Volume, and Balance Controls.
                    Volume with current value: 0.6666667  (range: 0.0 - 1.0)
                    Balance with current value: -2.9802322E-8  (range: -1.0 - 1.0)
     Beep, target
          Available controls:
               Beep Control containing Volume, Balance, and Mute Controls.
                    Volume with current value: 0.0  (range: 0.0 - 1.0)
                    Balance with current value: 0.0  (range: -1.0 - 1.0)
                    Mute Control with current value: true
This is the class I use for my test:
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.log4j.Logger;

public class LineinRecorder extends Thread {
     
     /** Logger instance */
     private static Logger log = Logger.getLogger(LineinRecorder.class);
     
     private TargetDataLine m_line;
     private AudioFileFormat.Type m_targetType;
     private AudioInputStream m_audioInputStream;
     private File m_outputFile;

     private LineinRecorder(TargetDataLine line, AudioFileFormat.Type m_type, File file) {
          m_line = line;
          m_targetType = m_type;
          m_audioInputStream = new AudioInputStream(line);
          m_outputFile = file;
     }

     /**
      * Starts the recording. To accomplish this, (i) the line is started and
      * (ii) the thread is started.
      */
     public void start() {
          /*
           * Starting the TargetDataLine. It tells the line that we now want to
           * read data from it. If this method isn't called, we won't be able to
           * read data from the line at all.
           */
          m_line.start();

          /*
           * Starting the thread. This call results in the method 'run()' (see
           * below) being called. There, the data is actually read from the line.
           */
          super.start();
     }

     /**
      * Stops the recording.
      * 
      * Note that stopping the thread explicitely is not necessary. Once no more
      * data can be read from the TargetDataLine, no more data be read from our
      * AudioInputStream. And if there is no more data from the AudioInputStream,
      * the method 'AudioSystem.write()' (called in 'run()' returns. Returning
      * from 'AudioSystem.write()' is followed by returning from 'run()', and
      * thus, the thread is terminated automatically.
      * 
      * It's not a good idea to call this method just 'stop()' because stop() is
      * a (deprecated) method of the class 'Thread'. And we don't want to
      * override this method.
      */
     public void stopRecording() {
          m_line.stop();
          m_line.close();
     }

     /**
      * Main working method. You may be surprised that here, just
      * 'AudioSystem.write()' is called. But internally, it works like this:
      * AudioSystem.write() contains a loop that is trying to read from the
      * passed AudioInputStream. Since we have a special AudioInputStream that
      * gets its data from a TargetDataLine, reading from the AudioInputStream
      * leads to reading from the TargetDataLine. The data read this way is then
      * written to the passed File. Before writing of audio data starts, a header
      * is written according to the desired audio file type. Reading continues
      * untill no more data can be read from the AudioInputStream. In our case,
      * this happens if no more data can be read from the TargetDataLine. This,
      * in turn, happens if the TargetDataLine is stopped or closed (which
      * implies stopping). (Also see the comment above.) Then, the file is closed
      * and 'AudioSystem.write()' returns.
      */
     public void run() {
          try {
               AudioSystem.write(m_audioInputStream, m_targetType, m_outputFile);
          } catch (IOException e) {
               e.printStackTrace();
          }
     }

     public static void record() {
          /*
           * We have made shure that there is only one command line argument. This
           * is taken as the filename of the soundfile to store to.
           */
          String strFilename = "audios/linein_rec.wav";
          File outputFile = new File(strFilename);

          /*
           * For simplicity, the audio data format used for recording is hardcoded
           * here. We use PCM 44.1 kHz, 16 bit signed, stereo.
           */
          AudioFormat audioFormat = new AudioFormat(8000.0F, 16, 1, true, false);

          /*
           * Now, we are trying to get a TargetDataLine. The TargetDataLine is
           * used later to read audio data from it. If requesting the line was
           * successful, we are opening it (important!).
           */
          Mixer.Info[] aInfos = AudioSystem.getMixerInfo();
          TargetDataLine targetDataLine = null;
          try {
                        // aInfos[2] is the only supported 
               targetDataLine = AudioSystem.getTargetDataLine(audioFormat,aInfos[2]);
               targetDataLine.open(audioFormat);
          } catch (LineUnavailableException e) {
               out("unable to get a recording line");
               e.printStackTrace();
               System.exit(1);
          }

          /*
           * Now, we are creating an AudioRecorder object. It contains the
           * logic of starting and stopping the recording, reading audio data from
           * the TargetDataLine and writing the data to a file.
           */
          LineinRecorder recorder = new LineinRecorder(targetDataLine, AudioFileFormat.Type.WAVE, outputFile);

          /*
           * Here, the recording is actually started.
           */
          recorder.start();
          out("Recording...");
          
          try {
               if (p==null) {
                    Thread.sleep(5000);
               } else {
                    Thread.sleep(p.getLong("registrationTime"));
               }
          } catch (InterruptedException e1) {
               e1.printStackTrace();
          }
          
          /*
           * Here, the recording is actually stopped.
           */
          recorder.stopRecording();
          out("Recording stopped.");
     }

     private static void out(String strMessage) {
          System.out.println(strMessage);
     }
}
So, when i call LineinRecorder.record() I get :
java.lang.IllegalArgumentException: Line unsupported: interface TargetDataLine supporting format PCM_SIGNED 8000.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
     at com.sun.media.sound.PortMixer.getLine(PortMixer.java:120)
     at javax.sound.sampled.AudioSystem.getTargetDataLine(AudioSystem.java:731)
     at capture.LineinRecorder.record(LineinRecorder.java:149)
     at entrypoint.MainEntry.main(MainEntry.java:73)
I don't understand why ? I don't know if I must specify explicitly     the line port but I don't know how to build TargetDataLine object.
Please help me I'm in trouble.

Any help is granted.
Regards,
edcruise.
  • 1. Re: Recording from LINE-IN problem
    captfoss Pro
    Currently Being Moderated
    http://www.vsj.co.uk/java/display.asp?id=370

    Read that...

    In order to record from the LINE_IN, you'll want to obtain the Port mixer, use the SelectionControl to turn all of the input ports off and the LINE_IN port on, and then just obtain a TargetDataLine to read from the port mixer.

    There's sample code and better explanation in the above article.
  • 2. Re: Recording from LINE-IN problem
    850977 Newbie
    Currently Being Moderated
    Thanks for the reply..
    I read the article and followed the example...but, I get:
    java.lang.IllegalArgumentException: No line matching interface TargetDataLine supporting format PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian is supported.
         at javax.sound.sampled.AudioSystem.getLine(AudioSystem.java:459)
         at entrypoint.MainEntry.main(MainEntry.java:133)
    Is there a way to list all available audio formats ? I wonder that does not exist a simple method to get them.
    Follow my code taken from above example:
    .....
    .....
                   File outputFile = new File("audios/linein-rec.wav");
                   AudioFormat recordingFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100.0F, 16, 2, 4, 44100.0F,
                             false);
                   DataLine.Info info = new DataLine.Info(TargetDataLine.class,
                             recordingFormat);
                   TargetDataLine recordLine = null;
                   try {
                        recordLine = (TargetDataLine) AudioSystem.getLine(info);
                        recordLine.open(recordingFormat);
                   } catch (LineUnavailableException e) {
                        System.out.println("unable to get a recording line");
                        e.printStackTrace();
                        System.exit(1);
                   }
                   
                   adjustRecordingVolume();
                   AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
                   KokRecorder recorder = new KokRecorder(recordLine, fileType, outputFile);
                   recorder.start();
                   System.out.println("Recording...");
                   try {
                        Thread.sleep(5000);
                   } catch (InterruptedException e1) {
                        e1.printStackTrace();
                   }
                   
                   recorder.stopRecording();
                   System.out.println("Recording stopped.");
    ......
    .....
         public static void adjustRecordingVolume() throws Exception {
              Port.Info recPortInfo = new Port.Info(Port.class, "Capture", true);
              Port recPort = (Port) AudioSystem.getLine(recPortInfo);
              setRecControlValue(recPort);
         }
         
         private static void setRecControlValue(Port inPort) throws Exception {
              inPort.open();
              Control[] controls = inPort.getControls();
              for (int i = 0; i < controls.length; i++) {
                   if (controls[i] instanceof CompoundControl) {
                        Control[] members = ((CompoundControl) controls).getMemberControls();
                        for (int j = 0; j < members.length; j++) {
                             setCtrl(members[j]);
                        } // for int j
                   } // if
                   else
                        setCtrl(controls[i]);
              } // for i
              inPort.close();
         }
         
         private static void setCtrl(Control ctl) {
              if(ctl.getType().toString().equals("Select")) {
                   ((BooleanControl)ctl).setValue(true);
              }
              if(ctl.getType().toString().equals("Volume")) {
                   FloatControl vol = (FloatControl) ctl;
                   float setVal = vol.getMinimum() + (vol.getMaximum() - vol.getMinimum()) * 0.8f;
                   vol.setValue(setVal);
              }
         }


    Thanks in advance.
    Regards,
    edcruise.
  • 3. Re: Recording from LINE-IN problem
    810604 Newbie
    Currently Being Moderated
    Here is some code to list the available mixers and the formats they support:
    class ListMixers {
        static PrintWriter out;
        
        static void listAll(final PrintWriter out) {
            ListMixers.out = out;
            Mixer.Info[] aInfos = AudioSystem.getMixerInfo();
            for (int i = 0; i < aInfos.length; i++) {
                try {
                    Mixer mixer = AudioSystem.getMixer(aInfos);
    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]");
    }
    }

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

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

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

    static 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);
    }
    }
    }
  • 4. Re: Recording from LINE-IN problem
    captfoss Pro
    Currently Being Moderated
    Is there a way to list all available audio formats ?
    You have to iterate through all of the lines in the system and get the list of supported formats from them... which is what the above code does.
    I wonder that does not exist a simple method to get them.
    Knowing that a particular format is available doesn't do you much good, you'd also need to know where it's available from... which is why the above isn't a horrible solution. You need to know which line supports that format, and which mixer that line comes from... so you have to iterate through the mixers, iterate through their lines, and then find the format.

    In the end, it's the only way to get everything you need.

    Is there a store in town that has an iPad2 in stock?

    Yes.

    Which store?

    Don't know. You'll have to call them to find out...

    Oh. Well, at least I know one of them has it...

    Yeah, but they might not still have it by the time you call them...

    Well crud...

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points