MediaRecorder.java revision e1a7ad23e0cefefc1e5c762a3d88179971077dcc
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import android.hardware.Camera;
20import android.os.Handler;
21import android.os.Looper;
22import android.os.Message;
23import android.util.Log;
24import android.view.Surface;
25import java.io.IOException;
26import java.io.FileNotFoundException;
27import java.io.FileOutputStream;
28import java.io.FileDescriptor;
29import java.lang.ref.WeakReference;
30
31/**
32 * Used to record audio and video. The recording control is based on a
33 * simple state machine (see below).
34 *
35 * <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" />
36 * </p>
37 *
38 * <p>A common case of using MediaRecorder to record audio works as follows:
39 *
40 * <pre>MediaRecorder recorder = new MediaRecorder();
41 * recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
42 * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
43 * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
44 * recorder.setOutputFile(PATH_NAME);
45 * recorder.prepare();
46 * recorder.start();   // Recording is now started
47 * ...
48 * recorder.stop();
49 * recorder.reset();   // You can reuse the object by going back to setAudioSource() step
50 * recorder.release(); // Now the object cannot be reused
51 * </pre>
52 *
53 * <p>See the <a href="{@docRoot}guide/topics/media/index.html">Audio and Video</a>
54 * documentation for additional help with using MediaRecorder.
55 */
56public class MediaRecorder
57{
58    static {
59        System.loadLibrary("media_jni");
60        native_init();
61    }
62    private final static String TAG = "MediaRecorder";
63
64    // The two fields below are accessed by native methods
65    @SuppressWarnings("unused")
66    private int mNativeContext;
67
68    @SuppressWarnings("unused")
69    private Surface mSurface;
70
71    private String mPath;
72    private FileDescriptor mFd;
73    private EventHandler mEventHandler;
74    private OnErrorListener mOnErrorListener;
75    private OnInfoListener mOnInfoListener;
76
77    /**
78     * Default constructor.
79     */
80    public MediaRecorder() {
81
82        Looper looper;
83        if ((looper = Looper.myLooper()) != null) {
84            mEventHandler = new EventHandler(this, looper);
85        } else if ((looper = Looper.getMainLooper()) != null) {
86            mEventHandler = new EventHandler(this, looper);
87        } else {
88            mEventHandler = null;
89        }
90
91        /* Native setup requires a weak reference to our object.
92         * It's easier to create it here than in C++.
93         */
94        native_setup(new WeakReference<MediaRecorder>(this));
95    }
96
97    /**
98     * Sets a Camera to use for recording. Use this function to switch
99     * quickly between preview and capture mode without a teardown of
100     * the camera object. Must call before prepare().
101     *
102     * @param c the Camera to use for recording
103     */
104    public native void setCamera(Camera c);
105
106    /**
107     * Sets a Surface to show a preview of recorded media (video). Calls this
108     * before prepare() to make sure that the desirable preview display is
109     * set.
110     *
111     * @param sv the Surface to use for the preview
112     */
113    public void setPreviewDisplay(Surface sv) {
114        mSurface = sv;
115    }
116
117    /**
118     * Defines the audio source. These constants are used with
119     * {@link MediaRecorder#setAudioSource(int)}.
120     */
121    public final class AudioSource {
122      /* Do not change these values without updating their counterparts
123       * in include/media/mediarecorder.h!
124       */
125        private AudioSource() {}
126        public static final int DEFAULT = 0;
127        /** Microphone audio source */
128        public static final int MIC = 1;
129
130        /** Voice call uplink (Tx) audio source */
131        public static final int VOICE_UPLINK = 2;
132
133        /** Voice call downlink (Rx) audio source */
134        public static final int VOICE_DOWNLINK = 3;
135
136        /** Voice call uplink + downlink audio source */
137        public static final int VOICE_CALL = 4;
138    }
139
140    /**
141     * Defines the video source. These constants are used with
142     * {@link MediaRecorder#setVideoSource(int)}.
143     */
144    public final class VideoSource {
145      /* Do not change these values without updating their counterparts
146       * in include/media/mediarecorder.h!
147       */
148        private VideoSource() {}
149        public static final int DEFAULT = 0;
150        /** Camera video source */
151        public static final int CAMERA = 1;
152    }
153
154    /**
155     * Defines the output format. These constants are used with
156     * {@link MediaRecorder#setOutputFormat(int)}.
157     */
158    public final class OutputFormat {
159      /* Do not change these values without updating their counterparts
160       * in include/media/mediarecorder.h!
161       */
162        private OutputFormat() {}
163        public static final int DEFAULT = 0;
164        /** 3GPP media file format*/
165        public static final int THREE_GPP = 1;
166        /** MPEG4 media file format*/
167        public static final int MPEG_4 = 2;
168
169        /** The following formats are audio only .aac or .amr formats **/
170        /** @deprecated  Deprecated in favor of AMR_NB */
171        /** TODO: change link when AMR_NB is exposed. Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB */
172        public static final int RAW_AMR = 3;
173        /** @hide AMR NB file format */
174        public static final int AMR_NB = 3;
175        /** @hide AMR WB file format */
176        public static final int AMR_WB = 4;
177        /** @hide AAC ADIF file format */
178        public static final int AAC_ADIF = 5;
179        /** @hide AAC ADTS file format */
180        public static final int AAC_ADTS = 6;
181    };
182
183    /**
184     * Defines the audio encoding. These constants are used with
185     * {@link MediaRecorder#setAudioEncoder(int)}.
186     */
187    public final class AudioEncoder {
188      /* Do not change these values without updating their counterparts
189       * in include/media/mediarecorder.h!
190       */
191        private AudioEncoder() {}
192        public static final int DEFAULT = 0;
193        /** AMR (Narrowband) audio codec */
194        public static final int AMR_NB = 1;
195        /** @hide AMR (Wideband) audio codec */
196        public static final int AMR_WB = 2;
197        /** @hide AAC audio codec */
198        public static final int AAC = 3;
199        /** @hide enhanced AAC audio codec */
200        public static final int AAC_PLUS = 4;
201        /** @hide enhanced AAC plus audio codec */
202        public static final int EAAC_PLUS = 5;
203    }
204
205    /**
206     * Defines the video encoding. These constants are used with
207     * {@link MediaRecorder#setVideoEncoder(int)}.
208     */
209    public final class VideoEncoder {
210      /* Do not change these values without updating their counterparts
211       * in include/media/mediarecorder.h!
212       */
213        private VideoEncoder() {}
214        public static final int DEFAULT = 0;
215        public static final int H263 = 1;
216        public static final int H264 = 2;
217        public static final int MPEG_4_SP = 3;
218    }
219
220
221    /**
222     * @hide Defines the audio sampling rate. This must be set before
223     * setAudioEncoder() or it will be ignored.
224     * This parameter is used with
225     * {@link MediaRecorder#setParameters(String)}.
226     */
227    public final class AudioParamSamplingRate {
228      /* Do not change these values without updating their counterparts
229       * in include/media/mediarecorder.h!
230       */
231        private AudioParamSamplingRate() {}
232        public static final String AUDIO_PARAM_SAMPLING_RATE_KEY = "audio-param-sampling-rate=";
233    }
234
235     /**
236     * @hide Defines the audio number of channels. This must be set before
237     * setAudioEncoder() or it will be ignored.
238     * This parameter is used with
239     * {@link MediaRecorder#setParameters(String)}.
240     */
241    public final class AudioParamChannels {
242      /* Do not change these values without updating their counterparts
243       * in include/media/mediarecorder.h!
244       */
245        private AudioParamChannels() {}
246        public static final String AUDIO_PARAM_NUMBER_OF_CHANNELS = "audio-param-number-of-channels=";
247    }
248
249     /**
250     * @hide Defines the audio encoding bitrate. This must be set before
251     * setAudioEncoder() or it will be ignored.
252     * This parameter is used with
253     * {@link MediaRecorder#setParameters(String)}.
254     */
255    public final class AudioParamEncodingBitrate{
256        private AudioParamEncodingBitrate() {}
257        public static final String AUDIO_PARAM_ENCODING_BITRATE = "audio-param-encoding-bitrate=";
258    }
259
260    /**
261     * Sets the audio source to be used for recording. If this method is not
262     * called, the output file will not contain an audio track. The source needs
263     * to be specified before setting recording-parameters or encoders. Call
264     * this only before setOutputFormat().
265     *
266     * @param audio_source the audio source to use
267     * @throws IllegalStateException if it is called after setOutputFormat()
268     * @see android.media.MediaRecorder.AudioSource
269     */
270    public native void setAudioSource(int audio_source)
271            throws IllegalStateException;
272
273    /**
274     * Gets the maximum value for audio sources.
275     * @see android.media.MediaRecorder.AudioSource
276     */
277    public static final int getAudioSourceMax() { return AudioSource.VOICE_CALL; }
278
279    /**
280     * Sets the video source to be used for recording. If this method is not
281     * called, the output file will not contain an video track. The source needs
282     * to be specified before setting recording-parameters or encoders. Call
283     * this only before setOutputFormat().
284     *
285     * @param video_source the video source to use
286     * @throws IllegalStateException if it is called after setOutputFormat()
287     * @see android.media.MediaRecorder.VideoSource
288     */
289    public native void setVideoSource(int video_source)
290            throws IllegalStateException;
291
292    /**
293     * Sets the format of the output file produced during recording. Call this
294     * after setAudioSource()/setVideoSource() but before prepare().
295     *
296     * <p>It is recommended to always use 3GP format when using the H.263
297     * video encoder and AMR audio encoder. Using an MPEG-4 container format
298     * may confuse some desktop players.</p>
299     *
300     * @param output_format the output format to use. The output format
301     * needs to be specified before setting recording-parameters or encoders.
302     * @throws IllegalStateException if it is called after prepare() or before
303     * setAudioSource()/setVideoSource().
304     * @see android.media.MediaRecorder.OutputFormat
305     */
306    public native void setOutputFormat(int output_format)
307            throws IllegalStateException;
308
309    /**
310     * Sets the width and height of the video to be captured.  Must be called
311     * after setVideoSource(). Call this after setOutFormat() but before
312     * prepare().
313     *
314     * @param width the width of the video to be captured
315     * @param height the height of the video to be captured
316     * @throws IllegalStateException if it is called after
317     * prepare() or before setOutputFormat()
318     */
319    public native void setVideoSize(int width, int height)
320            throws IllegalStateException;
321
322    /**
323     * Sets the frame rate of the video to be captured.  Must be called
324     * after setVideoSource(). Call this after setOutFormat() but before
325     * prepare().
326     *
327     * @param rate the number of frames per second of video to capture
328     * @throws IllegalStateException if it is called after
329     * prepare() or before setOutputFormat().
330     *
331     * NOTE: On some devices that have auto-frame rate, this sets the
332     * maximum frame rate, not a constant frame rate. Actual frame rate
333     * will vary according to lighting conditions.
334     */
335    public native void setVideoFrameRate(int rate) throws IllegalStateException;
336
337    /**
338     * Sets the maximum duration (in ms) of the recording session.
339     * Call this after setOutFormat() but before prepare().
340     * After recording reaches the specified duration, a notification
341     * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
342     * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
343     * and recording will be stopped. Stopping happens asynchronously, there
344     * is no guarantee that the recorder will have stopped by the time the
345     * listener is notified.
346     *
347     * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit)
348     *
349     */
350    public native void setMaxDuration(int max_duration_ms) throws IllegalArgumentException;
351
352    /**
353     * Sets the maximum filesize (in bytes) of the recording session.
354     * Call this after setOutFormat() but before prepare().
355     * After recording reaches the specified filesize, a notification
356     * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
357     * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
358     * and recording will be stopped. Stopping happens asynchronously, there
359     * is no guarantee that the recorder will have stopped by the time the
360     * listener is notified.
361     *
362     * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit)
363     *
364     */
365    public native void setMaxFileSize(long max_filesize_bytes) throws IllegalArgumentException;
366
367    /**
368     * Sets the audio encoder to be used for recording. If this method is not
369     * called, the output file will not contain an audio track. Call this after
370     * setOutputFormat() but before prepare().
371     *
372     * @param audio_encoder the audio encoder to use.
373     * @throws IllegalStateException if it is called before
374     * setOutputFormat() or after prepare().
375     * @see android.media.MediaRecorder.AudioEncoder
376     */
377    public native void setAudioEncoder(int audio_encoder)
378            throws IllegalStateException;
379
380    /**
381     * Sets the video encoder to be used for recording. If this method is not
382     * called, the output file will not contain an video track. Call this after
383     * setOutputFormat() and before prepare().
384     *
385     * @param video_encoder the video encoder to use.
386     * @throws IllegalStateException if it is called before
387     * setOutputFormat() or after prepare()
388     * @see android.media.MediaRecorder.VideoEncoder
389     */
390    public native void setVideoEncoder(int video_encoder)
391            throws IllegalStateException;
392
393    /**
394     * @hide Sets a parameter in the author engine.
395     *
396     * @param params the parameter to set.
397     * @see android.media.MediaRecorder.AudioParamSamplingRate
398     * @see android.media.MediaRecorder.AudioParamChannels
399     * @see android.media.MediaRecorder.AudioParamEncodingBitrate
400     */
401    public native void setParameters(String params);
402
403    /**
404     * Pass in the file descriptor of the file to be written. Call this after
405     * setOutputFormat() but before prepare().
406     *
407     * @param fd an open file descriptor to be written into.
408     * @throws IllegalStateException if it is called before
409     * setOutputFormat() or after prepare()
410     */
411    public void setOutputFile(FileDescriptor fd) throws IllegalStateException
412    {
413        mPath = null;
414        mFd = fd;
415    }
416
417    /**
418     * Sets the path of the output file to be produced. Call this after
419     * setOutputFormat() but before prepare().
420     *
421     * @param path The pathname to use.
422     * @throws IllegalStateException if it is called before
423     * setOutputFormat() or after prepare()
424     */
425    public void setOutputFile(String path) throws IllegalStateException
426    {
427        mFd = null;
428        mPath = path;
429    }
430
431    // native implementation
432    private native void _setOutputFile(FileDescriptor fd, long offset, long length)
433        throws IllegalStateException, IOException;
434    private native void _prepare() throws IllegalStateException, IOException;
435
436    /**
437     * Prepares the recorder to begin capturing and encoding data. This method
438     * must be called after setting up the desired audio and video sources,
439     * encoders, file format, etc., but before start().
440     *
441     * @throws IllegalStateException if it is called after
442     * start() or before setOutputFormat().
443     * @throws IOException if prepare fails otherwise.
444     */
445    public void prepare() throws IllegalStateException, IOException
446    {
447        if (mPath != null) {
448            FileOutputStream fos = new FileOutputStream(mPath);
449            try {
450                _setOutputFile(fos.getFD(), 0, 0);
451            } finally {
452                fos.close();
453            }
454        } else if (mFd != null) {
455            _setOutputFile(mFd, 0, 0);
456        } else {
457            throw new IOException("No valid output file");
458        }
459        _prepare();
460    }
461
462    /**
463     * Begins capturing and encoding data to the file specified with
464     * setOutputFile(). Call this after prepare().
465     *
466     * @throws IllegalStateException if it is called before
467     * prepare().
468     */
469    public native void start() throws IllegalStateException;
470
471    /**
472     * Stops recording. Call this after start(). Once recording is stopped,
473     * you will have to configure it again as if it has just been constructed.
474     *
475     * @throws IllegalStateException if it is called before start()
476     */
477    public native void stop() throws IllegalStateException;
478
479    /**
480     * Restarts the MediaRecorder to its idle state. After calling
481     * this method, you will have to configure it again as if it had just been
482     * constructed.
483     */
484    public void reset() {
485        native_reset();
486
487        // make sure none of the listeners get called anymore
488        mEventHandler.removeCallbacksAndMessages(null);
489    }
490
491    private native void native_reset();
492
493    /**
494     * Returns the maximum absolute amplitude that was sampled since the last
495     * call to this method. Call this only after the setAudioSource().
496     *
497     * @return the maximum absolute amplitude measured since the last call, or
498     * 0 when called for the first time
499     * @throws IllegalStateException if it is called before
500     * the audio source has been set.
501     */
502    public native int getMaxAmplitude() throws IllegalStateException;
503
504    /* Do not change this value without updating its counterpart
505     * in include/media/mediarecorder.h!
506     */
507    /** Unspecified media recorder error.
508     * @see android.media.MediaRecorder.OnErrorListener
509     */
510    public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1;
511
512    /**
513     * Interface definition for a callback to be invoked when an error
514     * occurs while recording.
515     */
516    public interface OnErrorListener
517    {
518        /**
519         * Called when an error occurs while recording.
520         *
521         * @param mr the MediaRecorder that encountered the error
522         * @param what    the type of error that has occurred:
523         * <ul>
524         * <li>{@link #MEDIA_RECORDER_ERROR_UNKNOWN}
525         * </ul>
526         * @param extra   an extra code, specific to the error type
527         */
528        void onError(MediaRecorder mr, int what, int extra);
529    }
530
531    /**
532     * Register a callback to be invoked when an error occurs while
533     * recording.
534     *
535     * @param l the callback that will be run
536     */
537    public void setOnErrorListener(OnErrorListener l)
538    {
539        mOnErrorListener = l;
540    }
541
542    /* Do not change these values without updating their counterparts
543     * in include/media/mediarecorder.h!
544     */
545    /** Unspecified media recorder error.
546     * @see android.media.MediaRecorder.OnInfoListener
547     */
548    public static final int MEDIA_RECORDER_INFO_UNKNOWN              = 1;
549    /** A maximum duration had been setup and has now been reached.
550     * @see android.media.MediaRecorder.OnInfoListener
551     */
552    public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
553    /** A maximum filesize had been setup and has now been reached.
554     * @see android.media.MediaRecorder.OnInfoListener
555     */
556    public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801;
557
558    /**
559     * Interface definition for a callback to be invoked when an error
560     * occurs while recording.
561     */
562    public interface OnInfoListener
563    {
564        /**
565         * Called when an error occurs while recording.
566         *
567         * @param mr the MediaRecorder that encountered the error
568         * @param what    the type of error that has occurred:
569         * <ul>
570         * <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
571         * <li>{@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
572         * <li>{@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
573         * </ul>
574         * @param extra   an extra code, specific to the error type
575         */
576        void onInfo(MediaRecorder mr, int what, int extra);
577    }
578
579    /**
580     * Register a callback to be invoked when an informational event occurs while
581     * recording.
582     *
583     * @param listener the callback that will be run
584     */
585    public void setOnInfoListener(OnInfoListener listener)
586    {
587        mOnInfoListener = listener;
588    }
589
590    private class EventHandler extends Handler
591    {
592        private MediaRecorder mMediaRecorder;
593
594        public EventHandler(MediaRecorder mr, Looper looper) {
595            super(looper);
596            mMediaRecorder = mr;
597        }
598
599        /* Do not change these values without updating their counterparts
600         * in include/media/mediarecorder.h!
601         */
602        private static final int MEDIA_RECORDER_EVENT_ERROR = 1;
603        private static final int MEDIA_RECORDER_EVENT_INFO  = 2;
604
605        @Override
606        public void handleMessage(Message msg) {
607            if (mMediaRecorder.mNativeContext == 0) {
608                Log.w(TAG, "mediarecorder went away with unhandled events");
609                return;
610            }
611            switch(msg.what) {
612            case MEDIA_RECORDER_EVENT_ERROR:
613                if (mOnErrorListener != null)
614                    mOnErrorListener.onError(mMediaRecorder, msg.arg1, msg.arg2);
615
616                return;
617
618            case MEDIA_RECORDER_EVENT_INFO:
619                if (mOnInfoListener != null)
620                    mOnInfoListener.onInfo(mMediaRecorder, msg.arg1, msg.arg2);
621
622                return;
623
624            default:
625                Log.e(TAG, "Unknown message type " + msg.what);
626                return;
627            }
628        }
629    }
630
631    /**
632     * Called from native code when an interesting event happens.  This method
633     * just uses the EventHandler system to post the event back to the main app thread.
634     * We use a weak reference to the original MediaRecorder object so that the native
635     * code is safe from the object disappearing from underneath it.  (This is
636     * the cookie passed to native_setup().)
637     */
638    private static void postEventFromNative(Object mediarecorder_ref,
639                                            int what, int arg1, int arg2, Object obj)
640    {
641        MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
642        if (mr == null) {
643            return;
644        }
645
646        if (mr.mEventHandler != null) {
647            Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
648            mr.mEventHandler.sendMessage(m);
649        }
650    }
651
652    /**
653     * Releases resources associated with this MediaRecorder object.
654     * It is good practice to call this method when you're done
655     * using the MediaRecorder.
656     */
657    public native void release();
658
659    private static native final void native_init();
660
661    private native final void native_setup(Object mediarecorder_this) throws IllegalStateException;
662
663    private native final void native_finalize();
664
665    @Override
666    protected void finalize() { native_finalize(); }
667}
668