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