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