Java Sound Capture from Microphone working code

Sound Capture: Record from Microphone and Save — Complete Java Example
 import java.io.ByteArrayInputStream;  
 import java.io.ByteArrayOutputStream;  
 import java.io.IOException;  
 import javax.sound.sampled.AudioFormat;  
 import javax.sound.sampled.AudioInputStream;  
 import javax.sound.sampled.AudioSystem;  
 import javax.sound.sampled.DataLine;  
 import javax.sound.sampled.TargetDataLine;  
 /**  
  * Reads data from the input channel and writes to the output stream  
  */  
 public class MicrophoneRecorder implements Runnable {  
   // record microphone && generate stream/byte array  
   private AudioInputStream audioInputStream;  
   private AudioFormat format;  
   public TargetDataLine line;  
   public Thread thread;  
   private double duration;  
   public MicrophoneRecorder(AudioFormat format) {  
     super();  
     this.format = format;  
   }  
   public void start() {  
     thread = new Thread(this);  
     thread.setName("Capture");  
     thread.start();  
   }  
   public void stop() {  
     thread = null;  
   }  
   @Override  
   public void run() {  
     duration = 0;  
     line = getTargetDataLineForRecord();  
     final ByteArrayOutputStream out = new ByteArrayOutputStream();  
     final int frameSizeInBytes = format.getFrameSize();  
     final int bufferLengthInFrames = line.getBufferSize() / 8;  
     final int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;  
     final byte[] data = new byte[bufferLengthInBytes];  
     int numBytesRead;  
     line.start();  
     while (thread != null) {  
       if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {  
         break;  
       }  
       out.write(data, 0, numBytesRead);  
     }  
     // we reached the end of the stream. stop and close the line.  
     line.stop();  
     line.close();  
     line = null;  
     // stop and close the output stream  
     try {  
       out.flush();  
       out.close();  
     } catch (final IOException ex) {  
       ex.printStackTrace();  
     }  
     // load bytes into the audio input stream for playback  
     final byte audioBytes[] = out.toByteArray();  
     final ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);  
     audioInputStream = new AudioInputStream(bais, format, 
                audioBytes.length / frameSizeInBytes);  
     final long milliseconds = (long) ((audioInputStream.getFrameLength()  
                     * 1000) / format.getFrameRate());  
     duration = milliseconds / 1000.0;  
     System.out.println(duration);  
     try {  
       audioInputStream.reset();  
       System.out.println("resetting...");  
     } catch (final Exception ex) {  
       ex.printStackTrace();  
       return;  
     }  
   }  
   private TargetDataLine getTargetDataLineForRecord() {  
     TargetDataLine line;  
     final DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);  
     if (!AudioSystem.isLineSupported(info)) {  
       return null;  
     }  
     // get and open the target data line for capture.  
     try {  
       line = (TargetDataLine) AudioSystem.getLine(info);  
       line.open(format, line.getBufferSize());  
     } catch (final Exception ex) {  
       return null;  
     }  
     return line;  
   }  
   public AudioInputStream getAudioInputStream() {  
     return audioInputStream;  
   }  
   public AudioFormat getFormat() {  
     return format;  
   }  
   public void setFormat(AudioFormat format) {  
     this.format = format;  
   }  
   public Thread getThread() {  
     return thread;  
   }  
   public double getDuration() {  
     return duration;  
   }  
 }  

Testing Code — Console Example (GUI Recommended)
A GUI is preferable for controlling the recording thread start/stop. Below is a minimal console test that records for 2 seconds and saves the result.

 public class Testss {  
   public static void main(String[] args) throws Exception {  
     // Use a common PCM format: 44100 Hz, 16-bit, mono, signed, little-endian  
     AudioFormat format = new AudioFormat(44100, 16, 1, true, true);  
     MicrophoneRecorder mr = new MicrophoneRecorder(format); 
     mr.start();  
     Thread.sleep(2000);  
     mr.stop();  
     // Save the recorded stream to a WAV file  
     WaveData wd = new WaveData();  
     Thread.sleep(3000);  
     wd.saveToFile("recording", Type.WAVE, mr.getAudioInputStream());  
   }  
 }  

Saving the AudioInputStream — WaveData Utility Method
   public boolean saveToFile(String name, AudioFileFormat.Type fileType,  
                AudioInputStream audioInputStream) {  
     System.out.println("Saving...");  
     if (null == name || null == fileType || audioInputStream == null) {  
       return false;  
     }  
     File myFile = new File( name+"." + fileType.getExtension());  
     // reset to the beginnning of the captured data  
     try {  
       audioInputStream.reset();  
     } catch (Exception e) {  
       return false;  
     }  
     int i = 0;  
     while (myFile.exists()) {  
       String temp = "" + i + myFile.getName();  
       myFile = new File(temp);  
     }  
     try {  
       AudioSystem.write(audioInputStream, fileType, myFile);  
     } catch (Exception ex) {  
       return false;  
     }  
     System.out.println("Saved " + myFile.getAbsolutePath());  
     return true;  
   }  

12 comments :

  1. Have no idea how much this helped me - it's tricky to find an example for this sort of thing!

    ReplyDelete
  2. hi am using above provided code but am getting the fallowing exception
    java.lang.Error: Unresolved compilation problem:
    The method getDefaultFormat() is undefined for the type AudioFormatUtil

    ReplyDelete
    Replies
    1. you need to remove

      AudioFormatUtil.getDefaultFormat()

      and pass an object of AudioFormat in place of "AudioFormatUtil.getDefaultFormat()" from the line below

      MicrophoneRecorder mr = new MicrophoneRecorder(AudioFormatUtil.getDefaultFormat());


      Please refer to this for detail about AudioFormat :
      http://docs.oracle.com/javase/1.4.2/docs/api/javax/sound/sampled/AudioFormat.html

      Delete
  3. hi,
    tell me please how do u know that line = (TargetDataLine) AudioSystem.getLine(info); points to the microphone? Why dont u use Port.Info.MICROPHONE explicitly ?

    ReplyDelete
  4. Port.Info shows only info about port. You can't record on this port :).

    ReplyDelete
  5. Which library contains WaveData class ?

    ReplyDelete
    Replies
    1. you can create your own WaveData class and put the method "saveToFile" there

      Delete
  6. how can I learn all this stuff ,i know core java..??

    ReplyDelete
  7. Hi guys, can you tell me something about quality of your recordings using this code? I wonder that low quality of my recordings cause bad sound card but i want to check your opinions. Thanks a lot!

    ReplyDelete
  8. HI, If i want to record audio and video together at same time how can i achieve it. If i use javacv ffmpegframerecorder it will record to another file and with above code i will save audio to another file then i need to merge it. Is there any option available to record and save video with audio in single step.not recording both in separate files. Thanks for your answer

    ReplyDelete
  9. MicrophoneRecorder mr = new MicrophoneRecorder( YOU NEED TO PASS OBJECT OF AudioFormat here);
    I am getting error in the above line.I am not getting what object I need to pass.

    ReplyDelete

Your Comment and Question will help to make this blog better...