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