Home | History | Annotate | Download | only in soundrecorder
      1 package com.android.soundrecorder;
      2 
      3 import java.io.File;
      4 import java.io.IOException;
      5 
      6 import android.content.Context;
      7 import android.media.AudioManager;
      8 import android.media.MediaPlayer;
      9 import android.media.MediaRecorder;
     10 import android.media.MediaPlayer.OnCompletionListener;
     11 import android.media.MediaPlayer.OnErrorListener;
     12 import android.os.Bundle;
     13 import android.os.Environment;
     14 import android.util.Log;
     15 
     16 public class Recorder implements OnCompletionListener, OnErrorListener {
     17     static final String SAMPLE_PREFIX = "recording";
     18     static final String SAMPLE_PATH_KEY = "sample_path";
     19     static final String SAMPLE_LENGTH_KEY = "sample_length";
     20 
     21     public static final int IDLE_STATE = 0;
     22     public static final int RECORDING_STATE = 1;
     23     public static final int PLAYING_STATE = 2;
     24 
     25     int mState = IDLE_STATE;
     26 
     27     public static final int NO_ERROR = 0;
     28     public static final int SDCARD_ACCESS_ERROR = 1;
     29     public static final int INTERNAL_ERROR = 2;
     30     public static final int IN_CALL_RECORD_ERROR = 3;
     31 
     32     public interface OnStateChangedListener {
     33         public void onStateChanged(int state);
     34         public void onError(int error);
     35     }
     36     OnStateChangedListener mOnStateChangedListener = null;
     37 
     38     long mSampleStart = 0;       // time at which latest record or play operation started
     39     int mSampleLength = 0;      // length of current sample
     40     File mSampleFile = null;
     41 
     42     MediaRecorder mRecorder = null;
     43     MediaPlayer mPlayer = null;
     44 
     45     public Recorder() {
     46     }
     47 
     48     public void saveState(Bundle recorderState) {
     49         recorderState.putString(SAMPLE_PATH_KEY, mSampleFile.getAbsolutePath());
     50         recorderState.putInt(SAMPLE_LENGTH_KEY, mSampleLength);
     51     }
     52 
     53     public int getMaxAmplitude() {
     54         if (mState != RECORDING_STATE)
     55             return 0;
     56         return mRecorder.getMaxAmplitude();
     57     }
     58 
     59     public void restoreState(Bundle recorderState) {
     60         String samplePath = recorderState.getString(SAMPLE_PATH_KEY);
     61         if (samplePath == null)
     62             return;
     63         int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1);
     64         if (sampleLength == -1)
     65             return;
     66 
     67         File file = new File(samplePath);
     68         if (!file.exists())
     69             return;
     70         if (mSampleFile != null
     71                 && mSampleFile.getAbsolutePath().compareTo(file.getAbsolutePath()) == 0)
     72             return;
     73 
     74         delete();
     75         mSampleFile = file;
     76         mSampleLength = sampleLength;
     77 
     78         signalStateChanged(IDLE_STATE);
     79     }
     80 
     81     public void setOnStateChangedListener(OnStateChangedListener listener) {
     82         mOnStateChangedListener = listener;
     83     }
     84 
     85     public int state() {
     86         return mState;
     87     }
     88 
     89     public int progress() {
     90         if (mState == RECORDING_STATE || mState == PLAYING_STATE)
     91             return (int) ((System.currentTimeMillis() - mSampleStart)/1000);
     92         return 0;
     93     }
     94 
     95     public int sampleLength() {
     96         return mSampleLength;
     97     }
     98 
     99     public File sampleFile() {
    100         return mSampleFile;
    101     }
    102 
    103     /**
    104      * Resets the recorder state. If a sample was recorded, the file is deleted.
    105      */
    106     public void delete() {
    107         stop();
    108 
    109         if (mSampleFile != null)
    110             mSampleFile.delete();
    111 
    112         mSampleFile = null;
    113         mSampleLength = 0;
    114 
    115         signalStateChanged(IDLE_STATE);
    116     }
    117 
    118     /**
    119      * Resets the recorder state. If a sample was recorded, the file is left on disk and will
    120      * be reused for a new recording.
    121      */
    122     public void clear() {
    123         stop();
    124 
    125         mSampleLength = 0;
    126 
    127         signalStateChanged(IDLE_STATE);
    128     }
    129 
    130     public void startRecording(int outputfileformat, String extension, Context context) {
    131         stop();
    132 
    133         if (mSampleFile == null) {
    134             File sampleDir = Environment.getExternalStorageDirectory();
    135             if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device.
    136                 sampleDir = new File("/sdcard/sdcard");
    137 
    138             try {
    139                 mSampleFile = File.createTempFile(SAMPLE_PREFIX, extension, sampleDir);
    140             } catch (IOException e) {
    141                 setError(SDCARD_ACCESS_ERROR);
    142                 return;
    143             }
    144         }
    145 
    146         mRecorder = new MediaRecorder();
    147         mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
    148         mRecorder.setOutputFormat(outputfileformat);
    149         mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
    150         mRecorder.setOutputFile(mSampleFile.getAbsolutePath());
    151 
    152         // Handle IOException
    153         try {
    154             mRecorder.prepare();
    155         } catch(IOException exception) {
    156             setError(INTERNAL_ERROR);
    157             mRecorder.reset();
    158             mRecorder.release();
    159             mRecorder = null;
    160             return;
    161         }
    162         // Handle RuntimeException if the recording couldn't start
    163         try {
    164             mRecorder.start();
    165         } catch (RuntimeException exception) {
    166             AudioManager audioMngr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    167             boolean isInCall = audioMngr.getMode() == AudioManager.MODE_IN_CALL;
    168             if (isInCall) {
    169                 setError(IN_CALL_RECORD_ERROR);
    170             } else {
    171                 setError(INTERNAL_ERROR);
    172             }
    173             mRecorder.reset();
    174             mRecorder.release();
    175             mRecorder = null;
    176             return;
    177         }
    178         mSampleStart = System.currentTimeMillis();
    179         setState(RECORDING_STATE);
    180     }
    181 
    182     public void stopRecording() {
    183         if (mRecorder == null)
    184             return;
    185 
    186         mRecorder.stop();
    187         mRecorder.release();
    188         mRecorder = null;
    189 
    190         mSampleLength = (int)( (System.currentTimeMillis() - mSampleStart)/1000 );
    191         setState(IDLE_STATE);
    192     }
    193 
    194     public void startPlayback() {
    195         stop();
    196 
    197         mPlayer = new MediaPlayer();
    198         try {
    199             mPlayer.setDataSource(mSampleFile.getAbsolutePath());
    200             mPlayer.setOnCompletionListener(this);
    201             mPlayer.setOnErrorListener(this);
    202             mPlayer.prepare();
    203             mPlayer.start();
    204         } catch (IllegalArgumentException e) {
    205             setError(INTERNAL_ERROR);
    206             mPlayer = null;
    207             return;
    208         } catch (IOException e) {
    209             setError(SDCARD_ACCESS_ERROR);
    210             mPlayer = null;
    211             return;
    212         }
    213 
    214         mSampleStart = System.currentTimeMillis();
    215         setState(PLAYING_STATE);
    216     }
    217 
    218     public void stopPlayback() {
    219         if (mPlayer == null) // we were not in playback
    220             return;
    221 
    222         mPlayer.stop();
    223         mPlayer.release();
    224         mPlayer = null;
    225         setState(IDLE_STATE);
    226     }
    227 
    228     public void stop() {
    229         stopRecording();
    230         stopPlayback();
    231     }
    232 
    233     public boolean onError(MediaPlayer mp, int what, int extra) {
    234         stop();
    235         setError(SDCARD_ACCESS_ERROR);
    236         return true;
    237     }
    238 
    239     public void onCompletion(MediaPlayer mp) {
    240         stop();
    241     }
    242 
    243     private void setState(int state) {
    244         if (state == mState)
    245             return;
    246 
    247         mState = state;
    248         signalStateChanged(mState);
    249     }
    250 
    251     private void signalStateChanged(int state) {
    252         if (mOnStateChangedListener != null)
    253             mOnStateChangedListener.onStateChanged(state);
    254     }
    255 
    256     private void setError(int error) {
    257         if (mOnStateChangedListener != null)
    258             mOnStateChangedListener.onError(error);
    259     }
    260 }
    261