Android Open Source - CopresenceDataCollector Ext Audio Recorder






From Project

Back to project page CopresenceDataCollector.

License

The source code is released under:

Copyright (c) 2014, Xiang Gao All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Re...

If you think the Android project CopresenceDataCollector 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.sesy.coco.datacollector.audio;
/*from  w  ww.j  av  a  2  s . co m*/
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

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

public class ExtAudioRecorder 
{
  //private final static int[] sampleRates = {44100, 22050, 11025, 8000};
  private final static int[] sampleRates = {44100, 44100, 44100, 44100};
  
  public static ExtAudioRecorder getInstanse(Boolean recordingCompressed)
  {
    ExtAudioRecorder result = null;
    
    if(recordingCompressed)
    {
      result = new ExtAudioRecorder(  false, 
                      AudioSource.MIC, 
                      sampleRates[3], 
                      AudioFormat.CHANNEL_IN_MONO,
                      AudioFormat.ENCODING_PCM_16BIT);
    }
    else
    {
      int i=0;
      do
      {
        result = new ExtAudioRecorder(  true, 
                        AudioSource.MIC, 
                        sampleRates[i], 
                        AudioFormat.CHANNEL_IN_MONO,
                        AudioFormat.ENCODING_PCM_16BIT);
        
      } while((++i<sampleRates.length) & !(result.getState() == ExtAudioRecorder.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;
  public static final boolean RECORDING_COMPRESSED = false;
  
  // 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;
  
  // Recorder used for compressed recording
  private MediaRecorder   mediaRecorder = 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(ExtAudioRecorder.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 ExtAudioRecorder(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_IN_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(ExtAudioRecorder.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);
      } else
      { // RECORDING_COMPRESSED
        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);        
      }
      cAmplitude = 0;
      filePath = null;
      state = State.INITIALIZING;
    } catch (Exception e)
    {
      if (e.getMessage() != null)
      {
        Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
      }
      else
      {
        Log.e(ExtAudioRecorder.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;
        if (!rUncompressed)
        {
          mediaRecorder.setOutputFile(filePath);          
        }
      }
    }
    catch (Exception e)
    {
      if (e.getMessage() != null)
      {
        Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
      }
      else
      {
        Log.e(ExtAudioRecorder.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)
    {
      if (rUncompressed)
      {
        int result = cAmplitude;
        cAmplitude = 0;
        return result;
      }
      else
      {
        try
        {
          return mediaRecorder.getMaxAmplitude();
        }
        catch (IllegalStateException e)
        {
          return 0;
        }
      }
    }
    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 (rUncompressed)
        {
          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(ExtAudioRecorder.class.getName(), "prepare() method called on uninitialized recorder");
            state = State.ERROR;
          }
        }
        else
        {
          mediaRecorder.prepare();
          state = State.READY;
        }
      }
      else
      {
        Log.e(ExtAudioRecorder.class.getName(), "prepare() method called on illegal state");
        release();
        state = State.ERROR;
      }
    }
    catch(Exception e)
    {
      if (e.getMessage() != null)
      {
        Log.e(ExtAudioRecorder.class.getName(), e.getMessage());
      }
      else
      {
        Log.e(ExtAudioRecorder.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(ExtAudioRecorder.class.getName(), "I/O exception occured while closing output file");
        }
        (new File(filePath)).delete();
      }
    }
    
    if (rUncompressed)
    {
      if (audioRecorder != null)
      {
        audioRecorder.release();
      }
    }
    else
    {
      if (mediaRecorder != null)
      {
        mediaRecorder.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
        if (rUncompressed)
        {
          audioRecorder = new AudioRecord(aSource, sRate, nChannels+1, aFormat, bufferSize);
        }
        else
        {
          mediaRecorder = new MediaRecorder();
          mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
          mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
          mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        }
        state = State.INITIALIZING;
      }
    }
    catch (Exception e)
    {
      Log.e(ExtAudioRecorder.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)
    {
      if (rUncompressed)
      {
        payloadSize = 0;
        audioRecorder.startRecording();
        audioRecorder.read(buffer, 0, buffer.length);
      }
      else
      {
        mediaRecorder.start();
      }
      state = State.RECORDING;
    }
    else
    {
      Log.e(ExtAudioRecorder.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)
    {
      if (rUncompressed)
      {
        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(ExtAudioRecorder.class.getName(), "I/O exception occured while closing output file");
          state = State.ERROR;
        }
      }
      else
      {
        mediaRecorder.stop();
      }
      state = State.STOPPED;
    }
    else
    {
      Log.e(ExtAudioRecorder.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

org.sesy.coco.datacollector.ARPWorker.java
org.sesy.coco.datacollector.AlarmService.java
org.sesy.coco.datacollector.AppLauncher.java
org.sesy.coco.datacollector.AudioProc.java
org.sesy.coco.datacollector.AudioWorker.java
org.sesy.coco.datacollector.BindActivity.java
org.sesy.coco.datacollector.BluetoothWorker.java
org.sesy.coco.datacollector.CellWorker.java
org.sesy.coco.datacollector.Constants.java
org.sesy.coco.datacollector.DaemonService.java
org.sesy.coco.datacollector.DataMonitor.java
org.sesy.coco.datacollector.GpsWorker.java
org.sesy.coco.datacollector.HelpActivity.java
org.sesy.coco.datacollector.MainActivity.java
org.sesy.coco.datacollector.MyPreference.java
org.sesy.coco.datacollector.MyWidgetProvider.java
org.sesy.coco.datacollector.PluginManager.java
org.sesy.coco.datacollector.PrefManager.java
org.sesy.coco.datacollector.ReportErrActivity.java
org.sesy.coco.datacollector.SDSetupActivity.java
org.sesy.coco.datacollector.SensorActivity.java
org.sesy.coco.datacollector.SensorListener.java
org.sesy.coco.datacollector.SensordroneWorker.java
org.sesy.coco.datacollector.SettingActivity.java
org.sesy.coco.datacollector.StatusActivity.java
org.sesy.coco.datacollector.StatusManager.java
org.sesy.coco.datacollector.TriggerService.java
org.sesy.coco.datacollector.UpdateWidgetService.java
org.sesy.coco.datacollector.WifiWorker.java
org.sesy.coco.datacollector.WorkerService.java
org.sesy.coco.datacollector.audio.Convolution.java
org.sesy.coco.datacollector.audio.CrossCorrelation.java
org.sesy.coco.datacollector.audio.ExtAudioRecorder.java
org.sesy.coco.datacollector.audio.XCorrAndDistFromWav.java
org.sesy.coco.datacollector.communication.HttpFileUploader.java
org.sesy.coco.datacollector.database.Entry.java
org.sesy.coco.datacollector.file.FileHelper.java
org.sesy.coco.datacollector.log.ConfigureLog4J.java
org.sesy.coco.datacollector.net.NetInfo.java
org.sesy.coco.datacollector.plugin.PlugInterface.java
wei.mark.standout.StandOutWindow.java
wei.mark.standout.Utils.java
wei.mark.standout.WindowCache.java
wei.mark.standout.constants.StandOutFlags.java
wei.mark.standout.ui.TouchInfo.java
wei.mark.standout.ui.Window.java