Android Open Source - rfcx-guardian-android Ext Audio Recorder Modified






From Project

Back to project page rfcx-guardian-android.

License

The source code is released under:

Apache License

If you think the Android project rfcx-guardian-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package org.rfcx.guardian.utility;
//w w  w . j a  v a 2s  .  c o  m
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import org.rfcx.guardian.audio.AudioCore;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;
import android.util.Log;

public class ExtAudioRecorderModified {

  public static ExtAudioRecorderModified getInstance() {
    ExtAudioRecorderModified result = null;
    do {
      result = new ExtAudioRecorderModified(
          true,
          AudioSource.MIC,
          AudioCore.CAPTURE_SAMPLE_RATE_HZ,
          AudioFormat.CHANNEL_CONFIGURATION_MONO,
          AudioFormat.ENCODING_PCM_16BIT);
    } while (!(result.getState() == ExtAudioRecorderModified.State.INITIALIZING));
    return result;
  }

  /**
   * INITIALIZING : recorder is initializing; READY : recorder has been
   * initialized, recorder not yet started RECORDING : recording ERROR :
   * reconstruction needed STOPPED: reset needed
   */
  public enum State {
    INITIALIZING, READY, RECORDING, ERROR, STOPPED
  };

  public static final boolean RECORDING_UNCOMPRESSED = true;

  // The interval in which the recorded samples are output to the file
  // Used only in uncompressed mode
  private static final int TIMER_INTERVAL = 120;

  // Toggles uncompressed recording on/off; RECORDING_UNCOMPRESSED /
  // RECORDING_COMPRESSED
  private boolean rUncompressed;

  // Recorder used for uncompressed recording
  private AudioRecord audioRecorder = null;

  // Stores current amplitude (only in uncompressed mode)
  private int cAmplitude = 0;

  // Output file path
  private String filePath = null;

  // Recorder state; see State
  private State state;

  // File writer (only in uncompressed mode)
  private RandomAccessFile randomAccessWriter;

  // Number of channels, sample rate, sample size(size in bits), buffer size,
  // audio source, sample size(see AudioFormat)
  private short nChannels;
  private int sRate;
  private short bSamples;
  private int bufferSize;
  private int aSource;
  private int aFormat;

  // Number of frames written to file on each output(only in uncompressed
  // mode)
  private int framePeriod;

  // Buffer for output(only in uncompressed mode)
  private byte[] buffer;

  // Number of bytes written to file after header(only in uncompressed mode)
  // after stop() is called, this size is written to the header/data chunk in
  // the wave file
  private int payloadSize;

  /**
   * 
   * Returns the state of the recorder in a RehearsalAudioRecord.State typed
   * object. Useful, as no exceptions are thrown.
   * 
   * @return recorder state
   */
  public State getState() {
    return state;
  }

  /*
   * 
   * Method used for recording.
   */
  private AudioRecord.OnRecordPositionUpdateListener updateListener = new AudioRecord.OnRecordPositionUpdateListener() {
    public void onPeriodicNotification(AudioRecord recorder) {
      audioRecorder.read(buffer, 0, buffer.length); // Fill buffer
      try {
        randomAccessWriter.write(buffer); // Write buffer to file
        payloadSize += buffer.length;
        if (bSamples == 16) {
          for (int i = 0; i < buffer.length / 2; i++) { // 16bit
                                  // sample
                                  // size
            short curSample = getShort(buffer[i * 2],
                buffer[i * 2 + 1]);
            if (curSample > cAmplitude) { // Check amplitude
              cAmplitude = curSample;
            }
          }
        } else { // 8bit sample size
          for (int i = 0; i < buffer.length; i++) {
            if (buffer[i] > cAmplitude) { // Check amplitude
              cAmplitude = buffer[i];
            }
          }
        }
      } catch (IOException e) {
        Log.e(ExtAudioRecorderModified.class.getName(),
            "Error occured in updateListener, recording is aborted");
        // stop();
      }
    }

    public void onMarkerReached(AudioRecord recorder) {
      // NOT USED
    }
  };

  /**
   * 
   * 
   * Default constructor
   * 
   * Instantiates a new recorder, in case of compressed recording the
   * parameters can be left as 0. In case of errors, no exception is thrown,
   * but the state is set to ERROR
   * 
   */
  public ExtAudioRecorderModified(boolean uncompressed, int audioSource,
      int sampleRate, int channelConfig, int audioFormat) {
    try {
      rUncompressed = uncompressed;
      if (rUncompressed) { // RECORDING_UNCOMPRESSED
        if (audioFormat == AudioFormat.ENCODING_PCM_16BIT) {
          bSamples = 16;
        } else {
          bSamples = 8;
        }

        if (channelConfig == AudioFormat.CHANNEL_CONFIGURATION_MONO) {
          nChannels = 1;
        } else {
          nChannels = 2;
        }

        aSource = audioSource;
        sRate = sampleRate;
        aFormat = audioFormat;

        framePeriod = sampleRate * TIMER_INTERVAL / 1000;
        bufferSize = framePeriod * 2 * bSamples * nChannels / 8;
        if (bufferSize < AudioRecord.getMinBufferSize(sampleRate,
            channelConfig, audioFormat)) { // Check to make sure
                            // buffer size is not
                            // smaller than the
                            // smallest allowed one
          bufferSize = AudioRecord.getMinBufferSize(sampleRate,
              channelConfig, audioFormat);
          // Set frame period and timer interval accordingly
          framePeriod = bufferSize / (2 * bSamples * nChannels / 8);
          Log.w(ExtAudioRecorderModified.class.getName(),
              "Increasing buffer size to "
                  + Integer.toString(bufferSize));
        }

        audioRecorder = new AudioRecord(audioSource, sampleRate,
            channelConfig, audioFormat, bufferSize);

        if (audioRecorder.getState() != AudioRecord.STATE_INITIALIZED)
          throw new Exception("AudioRecord initialization failed");
        audioRecorder.setRecordPositionUpdateListener(updateListener);
        audioRecorder.setPositionNotificationPeriod(framePeriod);
      }
      cAmplitude = 0;
      filePath = null;
      state = State.INITIALIZING;
    } catch (Exception e) {
      if (e.getMessage() != null) {
        Log.e(ExtAudioRecorderModified.class.getName(), e.getMessage());
      } else {
        Log.e(ExtAudioRecorderModified.class.getName(),
            "Unknown error occured while initializing recording");
      }
      state = State.ERROR;
    }
  }

  /**
   * Sets output file path, call directly after construction/reset.
   * 
   * @param output
   *            file path
   * 
   */
  public void setOutputFile(String argPath) {
    try {
      if (state == State.INITIALIZING) {
        filePath = argPath;
      }
    } catch (Exception e) {
      if (e.getMessage() != null) {
        Log.e(ExtAudioRecorderModified.class.getName(), e.getMessage());
      } else {
        Log.e(ExtAudioRecorderModified.class.getName(),
            "Unknown error occured while setting output path");
      }
      state = State.ERROR;
    }
  }

  /**
   * 
   * Returns the largest amplitude sampled since the last call to this method.
   * 
   * @return returns the largest amplitude since the last call, or 0 when not
   *         in recording state.
   * 
   */
  public int getMaxAmplitude() {
    if (state == State.RECORDING) {
      int result = cAmplitude;
      cAmplitude = 0;
      return result;
    } else {
      return 0;
    }
  }

  /**
   * 
   * Prepares the recorder for recording, in case the recorder is not in the
   * INITIALIZING state and the file path was not set the recorder is set to
   * the ERROR state, which makes a reconstruction necessary. In case
   * uncompressed recording is toggled, the header of the wave file is
   * written. In case of an exception, the state is changed to ERROR
   * 
   */
  public void prepare() {
    try {
      if (state == State.INITIALIZING) {
        if ((audioRecorder.getState() == AudioRecord.STATE_INITIALIZED)
            & (filePath != null)) {
          // write file header

          randomAccessWriter = new RandomAccessFile(filePath,
              "rw");

          randomAccessWriter.setLength(0); // Set file length to
                            // 0, to prevent
                            // unexpected
                            // behavior in case
                            // the file already
                            // existed
          randomAccessWriter.writeBytes("RIFF");
          randomAccessWriter.writeInt(0); // Final file size not
                          // known yet, write 0
          randomAccessWriter.writeBytes("WAVE");
          randomAccessWriter.writeBytes("fmt ");
          randomAccessWriter.writeInt(Integer.reverseBytes(16)); // Sub-chunk
                                      // size,
                                      // 16
                                      // for
                                      // PCM
          randomAccessWriter.writeShort(Short
              .reverseBytes((short) 1)); // AudioFormat, 1 for
                            // PCM
          randomAccessWriter.writeShort(Short
              .reverseBytes(nChannels));// Number of channels,
                            // 1 for mono, 2 for
                            // stereo
          randomAccessWriter
              .writeInt(Integer.reverseBytes(sRate)); // Sample
                                  // rate
          randomAccessWriter.writeInt(Integer.reverseBytes(sRate
              * bSamples * nChannels / 8)); // Byte rate,
                              // SampleRate*NumberOfChannels*BitsPerSample/8
          randomAccessWriter
              .writeShort(Short
                  .reverseBytes((short) (nChannels
                      * bSamples / 8))); // Block
                                // align,
                                // NumberOfChannels*BitsPerSample/8
          randomAccessWriter.writeShort(Short
              .reverseBytes(bSamples)); // Bits per sample
          randomAccessWriter.writeBytes("data");
          randomAccessWriter.writeInt(0); // Data chunk size not
                          // known yet, write 0

          buffer = new byte[framePeriod * bSamples / 8
              * nChannels];
          state = State.READY;
        } else {
          Log.e(ExtAudioRecorderModified.class.getName(),
              "prepare() method called on uninitialized recorder");
          state = State.ERROR;
        }

      } else {
        Log.e(ExtAudioRecorderModified.class.getName(),
            "prepare() method called on illegal state");
        release();
        state = State.ERROR;
      }
    } catch (Exception e) {
      if (e.getMessage() != null) {
        Log.e(ExtAudioRecorderModified.class.getName(), e.getMessage());
      } else {
        Log.e(ExtAudioRecorderModified.class.getName(),
            "Unknown error occured in prepare()");
      }
      state = State.ERROR;
    }
  }

  /**
   * 
   * 
   * Releases the resources associated with this class, and removes the
   * unnecessary files, when necessary
   * 
   */
  public void release() {
    if (state == State.RECORDING) {
      stop();
    } else {
      if ((state == State.READY) & (rUncompressed)) {
        try {
          randomAccessWriter.close(); // Remove prepared file
        } catch (IOException e) {
          Log.e(ExtAudioRecorderModified.class.getName(),
              "I/O exception occured while closing output file");
        }
        (new File(filePath)).delete();
      }
    }

    if (audioRecorder != null) {
      audioRecorder.release();
    }
  }

  /**
   * 
   * 
   * Resets the recorder to the INITIALIZING state, as if it was just created.
   * In case the class was in RECORDING state, the recording is stopped. In
   * case of exceptions the class is set to the ERROR state.
   * 
   */
  public void reset() {
    try {
      if (state != State.ERROR) {
        release();
        filePath = null; // Reset file path
        cAmplitude = 0; // Reset amplitude

        audioRecorder = new AudioRecord(aSource, sRate,
            nChannels + 1, aFormat, bufferSize);

        state = State.INITIALIZING;
      }
    } catch (Exception e) {
      Log.e(ExtAudioRecorderModified.class.getName(), e.getMessage());
      state = State.ERROR;
    }
  }

  /**
   * 
   * 
   * Starts the recording, and sets the state to RECORDING. Call after
   * prepare().
   * 
   */
  public void start() {
    if (state == State.READY) {

      payloadSize = 0;
      audioRecorder.startRecording();
      audioRecorder.read(buffer, 0, buffer.length);

      state = State.RECORDING;
    } else {
      Log.e(ExtAudioRecorderModified.class.getName(),
          "start() called on illegal state");
      state = State.ERROR;
    }
  }

  /**
   * 
   * 
   * Stops the recording, and sets the state to STOPPED. In case of further
   * usage, a reset is needed. Also finalizes the wave file in case of
   * uncompressed recording.
   * 
   */
  public void stop() {
    if (state == State.RECORDING) {

      audioRecorder.stop();

      try {
        randomAccessWriter.seek(4); // Write size to RIFF header
        randomAccessWriter.writeInt(Integer
            .reverseBytes(36 + payloadSize));

        randomAccessWriter.seek(40); // Write size to Subchunk2Size
                        // field
        randomAccessWriter.writeInt(Integer
            .reverseBytes(payloadSize));

        randomAccessWriter.close();
      } catch (IOException e) {
        Log.e(ExtAudioRecorderModified.class.getName(), "I/O exception occured while closing output file");
        state = State.ERROR;
      }

      state = State.STOPPED;
    } else {
      Log.e(ExtAudioRecorderModified.class.getName(), "stop() called on illegal state");
      state = State.ERROR;
    }
  }

  /*
   * 
   * Converts a byte[2] to a short, in LITTLE_ENDIAN format
   */
  private short getShort(byte argB1, byte argB2) {
    return (short) (argB1 | (argB2 << 8));
  }

}




Java Source Code List

net.sourceforge.javaFlacEncoder.ArrayRecycler.java
net.sourceforge.javaFlacEncoder.BlockEncodeRequest.java
net.sourceforge.javaFlacEncoder.BlockThreadManager.java
net.sourceforge.javaFlacEncoder.CRC16.java
net.sourceforge.javaFlacEncoder.CRC8.java
net.sourceforge.javaFlacEncoder.ChannelData.java
net.sourceforge.javaFlacEncoder.EncodedElement_32.java
net.sourceforge.javaFlacEncoder.EncodedElement.java
net.sourceforge.javaFlacEncoder.EncodingConfiguration.java
net.sourceforge.javaFlacEncoder.FLACEncoder.java
net.sourceforge.javaFlacEncoder.FLACFileOutputStream.java
net.sourceforge.javaFlacEncoder.FLACOutputStream.java
net.sourceforge.javaFlacEncoder.FLACStreamController.java
net.sourceforge.javaFlacEncoder.FLACStreamIdentifier.java
net.sourceforge.javaFlacEncoder.FLACStreamOutputStream.java
net.sourceforge.javaFlacEncoder.FLAC_ConsoleFileEncoder.java
net.sourceforge.javaFlacEncoder.FLAC_FileEncoder.java
net.sourceforge.javaFlacEncoder.FLAC_MD5.java
net.sourceforge.javaFlacEncoder.FrameHeader.java
net.sourceforge.javaFlacEncoder.FrameThread.java
net.sourceforge.javaFlacEncoder.Frame.java
net.sourceforge.javaFlacEncoder.LPC.java
net.sourceforge.javaFlacEncoder.MetadataBlockHeader.java
net.sourceforge.javaFlacEncoder.MetadataBlockStreamInfo.java
net.sourceforge.javaFlacEncoder.RiceEncoder.java
net.sourceforge.javaFlacEncoder.StreamConfiguration.java
net.sourceforge.javaFlacEncoder.Subframe_Constant.java
net.sourceforge.javaFlacEncoder.Subframe_Fixed.java
net.sourceforge.javaFlacEncoder.Subframe_LPC.java
net.sourceforge.javaFlacEncoder.Subframe_Verbatim.java
net.sourceforge.javaFlacEncoder.Subframe.java
net.sourceforge.javaFlacEncoder.UTF8Modified.java
org.rfcx.guardian.RfcxGuardianPrefs.java
org.rfcx.guardian.RfcxGuardian.java
org.rfcx.guardian.activity.MainActivity.java
org.rfcx.guardian.activity.PrefsActivity.java
org.rfcx.guardian.api.ApiCore.java
org.rfcx.guardian.audio.AudioCore.java
org.rfcx.guardian.database.AlertDb.java
org.rfcx.guardian.database.AudioDb.java
org.rfcx.guardian.database.DeviceStateDb.java
org.rfcx.guardian.database.SmsDb.java
org.rfcx.guardian.device.AirplaneMode.java
org.rfcx.guardian.device.CpuUsage.java
org.rfcx.guardian.device.DeviceState.java
org.rfcx.guardian.intentservice.ApiCheckInTriggerIntentService.java
org.rfcx.guardian.intentservice.AudioEncodeIntentService.java
org.rfcx.guardian.intentservice.ServiceMonitorIntentService.java
org.rfcx.guardian.receiver.AirplaneModeReceiver.java
org.rfcx.guardian.receiver.BootReceiver.java
org.rfcx.guardian.receiver.ConnectivityReceiver.java
org.rfcx.guardian.receiver.SmsReceiver.java
org.rfcx.guardian.service.ApiCheckInService.java
org.rfcx.guardian.service.AudioCaptureService.java
org.rfcx.guardian.service.CarrierCodeService.java
org.rfcx.guardian.service.DeviceStateService.java
org.rfcx.guardian.telecom.CarrierInteraction.java
org.rfcx.guardian.utility.DateTimeUtils.java
org.rfcx.guardian.utility.DeviceGuid.java
org.rfcx.guardian.utility.ExtAudioRecorderModified.java
org.rfcx.guardian.utility.FileUtils.java
org.rfcx.guardian.utility.HttpGet.java
org.rfcx.guardian.utility.HttpPostMultipart.java
org.rfcx.guardian.utility.TimeOfDay.java