@@ -32,7 +32,11 @@ Licensed to the Apache Software Foundation (ASF) under one
32
32
33
33
import java .io .File ;
34
34
import java .io .FileInputStream ;
35
+ import java .io .FileOutputStream ;
36
+ import java .io .InputStream ;
37
+ import java .io .OutputStream ;
35
38
import java .io .IOException ;
39
+ import java .util .LinkedList ;
36
40
37
41
/**
38
42
* This class implements the audio playback and recording capabilities used by Cordova.
@@ -81,7 +85,8 @@ public enum STATE { MEDIA_NONE,
81
85
private float duration = -1 ; // Duration of audio
82
86
83
87
private MediaRecorder recorder = null ; // Audio recording object
84
- private String tempFile = null ; // Temporary recording file name
88
+ private LinkedList <String > tempFiles = null ; // Temporary recording file name
89
+ private String tempFile = null ;
85
90
86
91
private MediaPlayer player = null ; // Audio player object
87
92
private boolean prepareOnly = true ; // playback after file prepare flag
@@ -98,13 +103,17 @@ public AudioPlayer(AudioHandler handler, String id, String file) {
98
103
this .id = id ;
99
104
this .audioFile = file ;
100
105
this .recorder = new MediaRecorder ();
106
+ this .tempFiles = new LinkedList <String >();
107
+ }
101
108
102
- if (Environment .getExternalStorageState ().equals (Environment .MEDIA_MOUNTED )) {
103
- this .tempFile = Environment .getExternalStorageDirectory ().getAbsolutePath () + "/tmprecording.3gp" ;
104
- } else {
105
- this .tempFile = "/data/data/" + handler .cordova .getActivity ().getPackageName () + "/cache/tmprecording.3gp" ;
106
- }
107
-
109
+ private String generateTempFile () {
110
+ String tempFileName = null ;
111
+ if (Environment .getExternalStorageState ().equals (Environment .MEDIA_MOUNTED )) {
112
+ tempFileName = Environment .getExternalStorageDirectory ().getAbsolutePath () + "/tmprecording-" + System .currentTimeMillis () + ".3gp" ;
113
+ } else {
114
+ tempFileName = "/data/data/" + handler .cordova .getActivity ().getPackageName () + "/cache/tmprecording-" + System .currentTimeMillis () + ".3gp" ;
115
+ }
116
+ return tempFileName ;
108
117
}
109
118
110
119
/**
@@ -121,7 +130,7 @@ public void destroy() {
121
130
this .player = null ;
122
131
}
123
132
if (this .recorder != null ) {
124
- this .stopRecording ();
133
+ this .stopRecording (true );
125
134
this .recorder .release ();
126
135
this .recorder = null ;
127
136
}
@@ -141,8 +150,9 @@ public void startRecording(String file) {
141
150
case NONE :
142
151
this .audioFile = file ;
143
152
this .recorder .setAudioSource (MediaRecorder .AudioSource .MIC );
144
- this .recorder .setOutputFormat (MediaRecorder .OutputFormat .DEFAULT ); // THREE_GPP);
145
- this .recorder .setAudioEncoder (MediaRecorder .AudioEncoder .DEFAULT ); //AMR_NB);
153
+ this .recorder .setOutputFormat (MediaRecorder .OutputFormat .RAW_AMR ); // THREE_GPP);
154
+ this .recorder .setAudioEncoder (MediaRecorder .AudioEncoder .AMR_NB ); //AMR_NB);
155
+ this .tempFile = generateTempFile ();
146
156
this .recorder .setOutputFile (this .tempFile );
147
157
try {
148
158
this .recorder .prepare ();
@@ -170,7 +180,6 @@ public void startRecording(String file) {
170
180
*/
171
181
public void moveFile (String file ) {
172
182
/* this is a hack to save the file as the specified name */
173
- File f = new File (this .tempFile );
174
183
175
184
if (!file .startsWith ("/" )) {
176
185
if (Environment .getExternalStorageState ().equals (Environment .MEDIA_MOUNTED )) {
@@ -180,30 +189,102 @@ public void moveFile(String file) {
180
189
}
181
190
}
182
191
183
- String logMsg = "renaming " + this .tempFile + " to " + file ;
184
- Log .d (LOG_TAG , logMsg );
185
- if (!f .renameTo (new File (file ))) Log .e (LOG_TAG , "FAILED " + logMsg );
192
+ int size = this .tempFiles .size ();
193
+ Log .d (LOG_TAG , "size = " + size );
194
+
195
+ // only one file so just copy it
196
+ if (size == 1 ) {
197
+ String logMsg = "renaming " + this .tempFile + " to " + file ;
198
+ Log .d (LOG_TAG , logMsg );
199
+ File f = new File (this .tempFile );
200
+ if (!f .renameTo (new File (file ))) Log .e (LOG_TAG , "FAILED " + logMsg );
201
+ }
202
+ // more than one file so the user must have pause recording. We'll need to concat files.
203
+ else {
204
+ FileOutputStream outputStream = null ;
205
+ try {
206
+ outputStream = new FileOutputStream (new File (file ));
207
+ FileInputStream inputStream = null ;
208
+ File inputFile = null ;
209
+ for (int i = 0 ; i < size ; i ++) {
210
+ try {
211
+ inputFile = new File (this .tempFiles .get (i ));
212
+ inputStream = new FileInputStream (inputFile );
213
+ copy (inputStream , outputStream , (i >0 ));
214
+ } catch (Exception e ) {
215
+ Log .e (LOG_TAG , e .getLocalizedMessage (), e );
216
+ } finally {
217
+ if (inputStream != null ) try {
218
+ inputStream .close ();
219
+ inputFile .delete ();
220
+ inputFile = null ;
221
+ } catch (Exception e ) {
222
+ Log .e (LOG_TAG , e .getLocalizedMessage (), e );
223
+ }
224
+ }
225
+ }
226
+ } catch (Exception e ) {
227
+ e .printStackTrace ();
228
+ } finally {
229
+ if (outputStream != null ) try {
230
+ outputStream .close ();
231
+ } catch (Exception e ) {
232
+ Log .e (LOG_TAG , e .getLocalizedMessage (), e );
233
+ }
234
+ }
235
+ }
236
+ }
237
+
238
+ private static long copy (InputStream from , OutputStream to , boolean skipHeader )
239
+ throws IOException {
240
+ byte [] buf = new byte [8096 ];
241
+ long total = 0 ;
242
+ if (skipHeader ) {
243
+ from .skip (6 );
244
+ }
245
+ while (true ) {
246
+ int r = from .read (buf );
247
+ if (r == -1 ) {
248
+ break ;
249
+ }
250
+ to .write (buf , 0 , r );
251
+ total += r ;
252
+ }
253
+ return total ;
186
254
}
187
255
188
256
/**
189
- * Stop recording and save to the file specified when recording started.
257
+ * Stop/Pause recording and save to the file specified when recording started.
190
258
*/
191
- public void stopRecording () {
259
+ public void stopRecording (boolean stop ) {
192
260
if (this .recorder != null ) {
193
261
try {
194
262
if (this .state == STATE .MEDIA_RUNNING ) {
195
263
this .recorder .stop ();
196
- this .setState (STATE .MEDIA_STOPPED );
197
264
}
198
265
this .recorder .reset ();
199
- this .moveFile (this .audioFile );
266
+ this .tempFiles .add (this .tempFile );
267
+ if (stop ) {
268
+ Log .d (LOG_TAG , "stopping recording" );
269
+ this .setState (STATE .MEDIA_STOPPED );
270
+ this .moveFile (this .audioFile );
271
+ } else {
272
+ Log .d (LOG_TAG , "pause recording" );
273
+ }
200
274
}
201
275
catch (Exception e ) {
202
276
e .printStackTrace ();
203
277
}
204
278
}
205
279
}
206
280
281
+ /**
282
+ * Resume recording and save to the file specified when recording started.
283
+ */
284
+ public void resumeRecording () {
285
+ startRecording (this .audioFile );
286
+ }
287
+
207
288
//==========================================================================
208
289
// Playback
209
290
//==========================================================================
0 commit comments