title: Android- AudioRecord has some skip beats when recording
body: <p>I have a simple application that records audio. At first, I used <code>MediaRecorder</code>. But the problem is I cannot record WAVE. (Or is it possible to record using <code>MediaRecorder</code> and has an output of WAV with headers?). So I followed an <a href="http://www.edumobile.org/android/android-development/audio-recording-in-wav-format-in-android-programming/" rel="nofollow noreferrer">example</a> :</p>
  
  <pre><code>        public class MainActivity extends Activity {
  
  
              private static final int RECORDER_BPP = 16;
              private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
              private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
              private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
              private static final int RECORDER_SAMPLERATE = 48000;
              private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
              private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
  
              MediaPlayer media = null;
              private AudioRecord recorder = null;
              private int bufferSize = 0;
              private Thread recordingThread = null;
              private boolean isRecording = false;
  
          @Override
          public void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
  
              setButtonHandlers();
              enableButtons(false);
  
              bufferSize = AudioRecord.getMinBufferSize(441000,
                      AudioFormat.CHANNEL_IN_STEREO,
                      AudioFormat.ENCODING_PCM_16BIT);
  
              System.out.println("buffer size: " + bufferSize);
          }
  
          private void setButtonHandlers() {
                  ((Button)findViewById(R.id.btnStart)).setOnClickListener(btnClick);
          ((Button)findViewById(R.id.btnStop)).setOnClickListener(btnClick);
          }
  
  
  
          private void enableButton(int id,boolean isEnable){
                  ((Button)findViewById(id)).setEnabled(isEnable);
          }
  
  
  
          private void enableButtons(boolean isRecording) {
                  enableButton(R.id.btnStart,!isRecording);
                  enableButton(R.id.btnStop,isRecording);
          }
  
  
  
          private String getFilename(){
                  String filepath = Environment.getExternalStorageDirectory().getPath();
                  File file = new File(filepath,AUDIO_RECORDER_FOLDER);
  
                  if(!file.exists()){
                          file.mkdirs();
                  }
  
                  return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV);
          }
  
  
  
          private String getTempFilename(){
                  String filepath = Environment.getExternalStorageDirectory().getPath();
                  File file = new File(filepath,AUDIO_RECORDER_FOLDER);
  
                  if(!file.exists()){
                          file.mkdirs();
                  }
  
                  File tempFile = new File(filepath,AUDIO_RECORDER_TEMP_FILE);
  
                  if(tempFile.exists())
                          tempFile.delete();
  
                  return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
          }
  
  
  
          private void startRecording(){
                  recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                                                  RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize);
                  int i = recorder.getState();
                  if(i==1)
                      recorder.startRecording();
  
                  isRecording = true;
  
                  recordingThread = new Thread(new Runnable() {
  
                          @Override
                          public void run() {
                                  writeAudioDataToFile();
  
                          }
                  },"AudioRecorder Thread");
  
                  recordingThread.start();
  
          }
  
  
  
          private void writeAudioDataToFile(){
                  byte data[] = new byte[bufferSize];
                  String filename = getTempFilename();
                  FileOutputStream os = null;
  
                  try {
                          os = new FileOutputStream(filename);
                  } catch (FileNotFoundException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                  }
  
                  int read = 0;
  
                  if(null != os){
                          while(isRecording){
                                  read = recorder.read(data, 0, bufferSize);
  
                                  if(AudioRecord.ERROR_INVALID_OPERATION != read){
                                          try {
                                                  os.write(data);
                                          } catch (IOException e) {
                                                  e.printStackTrace();
                                          }
                                  }
                          }
  
                          try {
                                  os.close();
                          } catch (IOException e) {
                                  e.printStackTrace();
                          }
                  }
          }
  
  
          private void stopRecording(){
                  if(null != recorder){
                          isRecording = false;
  
                          int i = recorder.getState();
                          if(i==1)
                              recorder.stop();
                          recorder.release();
  
                          recorder = null;
                          recordingThread = null;
                  }
  
                  if(media != null) media.stop();
                  copyWaveFile(getTempFilename(),getFilename());
                  deleteTempFile();
          }
  
          private void deleteTempFile() {
                  File file = new File(getTempFilename());
  
                  file.delete();
          }
  
          private void copyWaveFile(String inFilename,String outFilename){
                  FileInputStream in = null;
                  FileOutputStream out = null;
                  long totalAudioLen = 0;
                  long totalDataLen = totalAudioLen + 36;
                  long longSampleRate = RECORDER_SAMPLERATE;
                  int channels = 2;
                  long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8;
  
                  byte[] data = new byte[bufferSize];
  
                  try {
                          in = new FileInputStream(inFilename);
                          out = new FileOutputStream(outFilename);
                          totalAudioLen = in.getChannel().size();
                          totalDataLen = totalAudioLen + 36;
  
                          AppLog.logString("File size: " + totalDataLen);
  
                          WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                                          longSampleRate, channels, byteRate);
  
                          while(in.read(data) != -1){
                                  out.write(data);
                          }
  
                          in.close();
                          out.close();
                  } catch (FileNotFoundException e) {
                          e.printStackTrace();
                  } catch (IOException e) {
                          e.printStackTrace();
                  }
          }
  
          private void WriteWaveFileHeader(
                          FileOutputStream out, long totalAudioLen,
                          long totalDataLen, long longSampleRate, int channels,
                          long byteRate) throws IOException {
  
                  byte[] header = new byte[44];
  
                  header[0] = 'R';  // RIFF/WAVE header
                  header[1] = 'I';
                  header[2] = 'F';
                  header[3] = 'F';
                  header[4] = (byte) (totalDataLen &amp; 0xff);
                  header[5] = (byte) ((totalDataLen &gt;&gt; 8) &amp; 0xff);
                  header[6] = (byte) ((totalDataLen &gt;&gt; 16) &amp; 0xff);
                  header[7] = (byte) ((totalDataLen &gt;&gt; 24) &amp; 0xff);
                  header[8] = 'W';
                  header[9] = 'A';
                  header[10] = 'V';
                  header[11] = 'E';
                  header[12] = 'f';  // 'fmt ' chunk
                  header[13] = 'm';
                  header[14] = 't';
                  header[15] = ' ';
                  header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
                  header[17] = 0;
                  header[18] = 0;
                  header[19] = 0;
                  header[20] = 1;  // format = 1
                  header[21] = 0;
                  header[22] = (byte) channels;
                  header[23] = 0;
                  header[24] = (byte) (longSampleRate &amp; 0xff);
                  header[25] = (byte) ((longSampleRate &gt;&gt; 8) &amp; 0xff);
                  header[26] = (byte) ((longSampleRate &gt;&gt; 16) &amp; 0xff);
                  header[27] = (byte) ((longSampleRate &gt;&gt; 24) &amp; 0xff);
                  header[28] = (byte) (byteRate &amp; 0xff);
                  header[29] = (byte) ((byteRate &gt;&gt; 8) &amp; 0xff);
                  header[30] = (byte) ((byteRate &gt;&gt; 16) &amp; 0xff);
                  header[31] = (byte) ((byteRate &gt;&gt; 24) &amp; 0xff);
                  header[32] = (byte) (2 * 16 / 8);  // block align
                  header[33] = 0;
                  header[34] = RECORDER_BPP;  // bits per sample
                  header[35] = 0;
                  header[36] = 'd';
                  header[37] = 'a';
                  header[38] = 't';
                  header[39] = 'a';
                  header[40] = (byte) (totalAudioLen &amp; 0xff);
                  header[41] = (byte) ((totalAudioLen &gt;&gt; 8) &amp; 0xff);
                  header[42] = (byte) ((totalAudioLen &gt;&gt; 16) &amp; 0xff);
                  header[43] = (byte) ((totalAudioLen &gt;&gt; 24) &amp; 0xff);
  
                  out.write(header, 0, 44);
          }
  
          private View.OnClickListener btnClick = new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                          switch(v.getId()){
                                  case R.id.btnStart:{
                                          AppLog.logString("Start Recording");
  
                                          enableButtons(true);
                                          startRecording();
  
                                          break;
                                  }
                                  case R.id.btnStop:{
                                          AppLog.logString("Start Recording");
  
                                              enableButtons(false);
                                              stopRecording();
  
                                              break;
                                      }
                              }
                      }
              }; 
          }
  </code></pre>
  
  <p>But what happens is when i record a metronome, I noticed an irregularity. Looking at the waveform, it has something like this..</p>
  
  <p><img src="https://i.stack.imgur.com/igVj2.png" alt="enter image description here"></p>
  
  <p>What could have gone wrong? </p>
  
  <p>Your help would be greatly appreciated.</p>
  
  <p>[Additional]</p>
  
  <p>In other cases: this is what happen:</p>
  
  <p><img src="https://i.stack.imgur.com/qWkN4.png" alt="enter image description here"></p>
  
  <p>I don't　know what happened to the recording at the certain time, the one inside the green circle. Did the recorder stopped at that time then started again? </p>