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 
17 package android.media;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.FloatRange;
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.RequiresPermission;
25 import android.annotation.SystemApi;
26 import android.app.ActivityThread;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.hardware.Camera;
29 import android.os.Build;
30 import android.os.Handler;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.PersistableBundle;
34 import android.util.ArrayMap;
35 import android.util.Log;
36 import android.util.Pair;
37 import android.view.Surface;
38 
39 import com.android.internal.annotations.GuardedBy;
40 import com.android.internal.util.Preconditions;
41 
42 import java.io.File;
43 import java.io.FileDescriptor;
44 import java.io.IOException;
45 import java.io.RandomAccessFile;
46 import java.lang.annotation.Retention;
47 import java.lang.annotation.RetentionPolicy;
48 import java.lang.ref.WeakReference;
49 import java.util.ArrayList;
50 import java.util.List;
51 import java.util.concurrent.Executor;
52 
53 /**
54  * Used to record audio and video. The recording control is based on a
55  * simple state machine (see below).
56  *
57  * <p><img src="{@docRoot}images/mediarecorder_state_diagram.gif" border="0" />
58  * </p>
59  *
60  * <p>A common case of using MediaRecorder to record audio works as follows:
61  *
62  * <pre>MediaRecorder recorder = new MediaRecorder();
63  * recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
64  * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
65  * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
66  * recorder.setOutputFile(PATH_NAME);
67  * recorder.prepare();
68  * recorder.start();   // Recording is now started
69  * ...
70  * recorder.stop();
71  * recorder.reset();   // You can reuse the object by going back to setAudioSource() step
72  * recorder.release(); // Now the object cannot be reused
73  * </pre>
74  *
75  * <p>Applications may want to register for informational and error
76  * events in order to be informed of some internal update and possible
77  * runtime errors during recording. Registration for such events is
78  * done by setting the appropriate listeners (via calls
79  * (to {@link #setOnInfoListener(OnInfoListener)}setOnInfoListener and/or
80  * {@link #setOnErrorListener(OnErrorListener)}setOnErrorListener).
81  * In order to receive the respective callback associated with these listeners,
82  * applications are required to create MediaRecorder objects on threads with a
83  * Looper running (the main UI thread by default already has a Looper running).
84  *
85  * <p><strong>Note:</strong> Currently, MediaRecorder does not work on the emulator.
86  *
87  * <div class="special reference">
88  * <h3>Developer Guides</h3>
89  * <p>For more information about how to use MediaRecorder for recording video, read the
90  * <a href="{@docRoot}guide/topics/media/camera.html#capture-video">Camera</a> developer guide.
91  * For more information about how to use MediaRecorder for recording sound, read the
92  * <a href="{@docRoot}guide/topics/media/audio-capture.html">Audio Capture</a> developer guide.</p>
93  * </div>
94  */
95 public class MediaRecorder implements AudioRouting,
96                                       AudioRecordingMonitor,
97                                       AudioRecordingMonitorClient,
98                                       MicrophoneDirection
99 {
100     static {
101         System.loadLibrary("media_jni");
native_init()102         native_init();
103     }
104     private final static String TAG = "MediaRecorder";
105 
106     // The two fields below are accessed by native methods
107     @SuppressWarnings("unused")
108     private long mNativeContext;
109 
110     @SuppressWarnings("unused")
111     @UnsupportedAppUsage
112     private Surface mSurface;
113 
114     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
115     private String mPath;
116     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
117     private FileDescriptor mFd;
118     private File mFile;
119     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
120     private EventHandler mEventHandler;
121     @UnsupportedAppUsage
122     private OnErrorListener mOnErrorListener;
123     @UnsupportedAppUsage
124     private OnInfoListener mOnInfoListener;
125 
126     private int mChannelCount;
127 
128     /**
129      * Default constructor.
130      */
MediaRecorder()131     public MediaRecorder() {
132 
133         Looper looper;
134         if ((looper = Looper.myLooper()) != null) {
135             mEventHandler = new EventHandler(this, looper);
136         } else if ((looper = Looper.getMainLooper()) != null) {
137             mEventHandler = new EventHandler(this, looper);
138         } else {
139             mEventHandler = null;
140         }
141 
142         mChannelCount = 1;
143         String packageName = ActivityThread.currentPackageName();
144         /* Native setup requires a weak reference to our object.
145          * It's easier to create it here than in C++.
146          */
147         native_setup(new WeakReference<MediaRecorder>(this), packageName,
148                 ActivityThread.currentOpPackageName());
149     }
150 
151     /**
152      * Sets a {@link android.hardware.Camera} to use for recording.
153      *
154      * <p>Use this function to switch quickly between preview and capture mode without a teardown of
155      * the camera object. {@link android.hardware.Camera#unlock()} should be called before
156      * this. Must call before {@link #prepare}.</p>
157      *
158      * @param c the Camera to use for recording
159      * @deprecated Use {@link #getSurface} and the {@link android.hardware.camera2} API instead.
160      */
161     @Deprecated
setCamera(Camera c)162     public native void setCamera(Camera c);
163 
164     /**
165      * Gets the surface to record from when using SURFACE video source.
166      *
167      * <p> May only be called after {@link #prepare}. Frames rendered to the Surface before
168      * {@link #start} will be discarded.</p>
169      *
170      * @throws IllegalStateException if it is called before {@link #prepare}, after
171      * {@link #stop}, or is called when VideoSource is not set to SURFACE.
172      * @see android.media.MediaRecorder.VideoSource
173      */
getSurface()174     public native Surface getSurface();
175 
176     /**
177      * Configures the recorder to use a persistent surface when using SURFACE video source.
178      * <p> May only be called before {@link #prepare}. If called, {@link #getSurface} should
179      * not be used and will throw IllegalStateException. Frames rendered to the Surface
180      * before {@link #start} will be discarded.</p>
181 
182      * @param surface a persistent input surface created by
183      *           {@link MediaCodec#createPersistentInputSurface}
184      * @throws IllegalStateException if it is called after {@link #prepare} and before
185      * {@link #stop}.
186      * @throws IllegalArgumentException if the surface was not created by
187      *           {@link MediaCodec#createPersistentInputSurface}.
188      * @see MediaCodec#createPersistentInputSurface
189      * @see MediaRecorder.VideoSource
190      */
setInputSurface(@onNull Surface surface)191     public void setInputSurface(@NonNull Surface surface) {
192         if (!(surface instanceof MediaCodec.PersistentSurface)) {
193             throw new IllegalArgumentException("not a PersistentSurface");
194         }
195         native_setInputSurface(surface);
196     }
197 
native_setInputSurface(@onNull Surface surface)198     private native final void native_setInputSurface(@NonNull Surface surface);
199 
200     /**
201      * Sets a Surface to show a preview of recorded media (video). Calls this
202      * before prepare() to make sure that the desirable preview display is
203      * set. If {@link #setCamera(Camera)} is used and the surface has been
204      * already set to the camera, application do not need to call this. If
205      * this is called with non-null surface, the preview surface of the camera
206      * will be replaced by the new surface. If this method is called with null
207      * surface or not called at all, media recorder will not change the preview
208      * surface of the camera.
209      *
210      * @param sv the Surface to use for the preview
211      * @see android.hardware.Camera#setPreviewDisplay(android.view.SurfaceHolder)
212      */
setPreviewDisplay(Surface sv)213     public void setPreviewDisplay(Surface sv) {
214         mSurface = sv;
215     }
216 
217     /**
218      * Defines the audio source.
219      * An audio source defines both a default physical source of audio signal, and a recording
220      * configuration. These constants are for instance used
221      * in {@link MediaRecorder#setAudioSource(int)} or
222      * {@link AudioRecord.Builder#setAudioSource(int)}.
223      */
224     public final class AudioSource {
225 
AudioSource()226         private AudioSource() {}
227 
228         /** @hide */
229         public final static int AUDIO_SOURCE_INVALID = -1;
230 
231       /* Do not change these values without updating their counterparts
232        * in system/media/audio/include/system/audio.h!
233        */
234 
235         /** Default audio source **/
236         public static final int DEFAULT = 0;
237 
238         /** Microphone audio source */
239         public static final int MIC = 1;
240 
241         /** Voice call uplink (Tx) audio source.
242          * <p>
243          * Capturing from <code>VOICE_UPLINK</code> source requires the
244          * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
245          * This permission is reserved for use by system components and is not available to
246          * third-party applications.
247          * </p>
248          */
249         public static final int VOICE_UPLINK = 2;
250 
251         /** Voice call downlink (Rx) audio source.
252          * <p>
253          * Capturing from <code>VOICE_DOWNLINK</code> source requires the
254          * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
255          * This permission is reserved for use by system components and is not available to
256          * third-party applications.
257          * </p>
258          */
259         public static final int VOICE_DOWNLINK = 3;
260 
261         /** Voice call uplink + downlink audio source
262          * <p>
263          * Capturing from <code>VOICE_CALL</code> source requires the
264          * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
265          * This permission is reserved for use by system components and is not available to
266          * third-party applications.
267          * </p>
268          */
269         public static final int VOICE_CALL = 4;
270 
271         /** Microphone audio source tuned for video recording, with the same orientation
272          *  as the camera if available. */
273         public static final int CAMCORDER = 5;
274 
275         /** Microphone audio source tuned for voice recognition. */
276         public static final int VOICE_RECOGNITION = 6;
277 
278         /** Microphone audio source tuned for voice communications such as VoIP. It
279          *  will for instance take advantage of echo cancellation or automatic gain control
280          *  if available.
281          */
282         public static final int VOICE_COMMUNICATION = 7;
283 
284         /**
285          * Audio source for a submix of audio streams to be presented remotely.
286          * <p>
287          * An application can use this audio source to capture a mix of audio streams
288          * that should be transmitted to a remote receiver such as a Wifi display.
289          * While recording is active, these audio streams are redirected to the remote
290          * submix instead of being played on the device speaker or headset.
291          * </p><p>
292          * Certain streams are excluded from the remote submix, including
293          * {@link AudioManager#STREAM_RING}, {@link AudioManager#STREAM_ALARM},
294          * and {@link AudioManager#STREAM_NOTIFICATION}.  These streams will continue
295          * to be presented locally as usual.
296          * </p><p>
297          * Capturing the remote submix audio requires the
298          * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
299          * This permission is reserved for use by system components and is not available to
300          * third-party applications.
301          * </p>
302          */
303         @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
304         public static final int REMOTE_SUBMIX = 8;
305 
306         /** Microphone audio source tuned for unprocessed (raw) sound if available, behaves like
307          *  {@link #DEFAULT} otherwise. */
308         public static final int UNPROCESSED = 9;
309 
310 
311         /**
312          * Source for capturing audio meant to be processed in real time and played back for live
313          * performance (e.g karaoke).
314          * <p>
315          * The capture path will minimize latency and coupling with
316          * playback path.
317          * </p>
318          */
319         public static final int VOICE_PERFORMANCE = 10;
320 
321         /**
322          * Source for an echo canceller to capture the reference signal to be cancelled.
323          * <p>
324          * The echo reference signal will be captured as close as possible to the DAC in order
325          * to include all post processing applied to the playback path.
326          * </p><p>
327          * Capturing the echo reference requires the
328          * {@link android.Manifest.permission#CAPTURE_AUDIO_OUTPUT} permission.
329          * This permission is reserved for use by system components and is not available to
330          * third-party applications.
331          * </p>
332          * @hide
333          */
334         @SystemApi
335         @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
336         public static final int ECHO_REFERENCE = 1997;
337 
338         /**
339          * Audio source for capturing broadcast radio tuner output.
340          * @hide
341          */
342         @SystemApi
343         public static final int RADIO_TUNER = 1998;
344 
345         /**
346          * Audio source for preemptible, low-priority software hotword detection
347          * It presents the same gain and pre-processing tuning as {@link #VOICE_RECOGNITION}.
348          * <p>
349          * An application should use this audio source when it wishes to do
350          * always-on software hotword detection, while gracefully giving in to any other application
351          * that might want to read from the microphone.
352          * </p>
353          * This is a hidden audio source.
354          * @hide
355          */
356         @SystemApi
357         @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
358         public static final int HOTWORD = 1999;
359     }
360 
361     /** @hide */
362     @IntDef({
363         AudioSource.DEFAULT,
364         AudioSource.MIC,
365         AudioSource.VOICE_UPLINK,
366         AudioSource.VOICE_DOWNLINK,
367         AudioSource.VOICE_CALL,
368         AudioSource.CAMCORDER,
369         AudioSource.VOICE_RECOGNITION,
370         AudioSource.VOICE_COMMUNICATION,
371         AudioSource.UNPROCESSED,
372         AudioSource.VOICE_PERFORMANCE,
373     })
374     @Retention(RetentionPolicy.SOURCE)
375     public @interface Source {}
376 
377     // TODO make AudioSource static (API change) and move this method inside the AudioSource class
378     /**
379      * @hide
380      * @param source An audio source to test
381      * @return true if the source is only visible to system components
382      */
isSystemOnlyAudioSource(int source)383     public static boolean isSystemOnlyAudioSource(int source) {
384         switch(source) {
385         case AudioSource.DEFAULT:
386         case AudioSource.MIC:
387         case AudioSource.VOICE_UPLINK:
388         case AudioSource.VOICE_DOWNLINK:
389         case AudioSource.VOICE_CALL:
390         case AudioSource.CAMCORDER:
391         case AudioSource.VOICE_RECOGNITION:
392         case AudioSource.VOICE_COMMUNICATION:
393         //case REMOTE_SUBMIX:  considered "system" as it requires system permissions
394         case AudioSource.UNPROCESSED:
395         case AudioSource.VOICE_PERFORMANCE:
396             return false;
397         default:
398             return true;
399         }
400     }
401 
402     /** @hide */
toLogFriendlyAudioSource(int source)403     public static final String toLogFriendlyAudioSource(int source) {
404         switch(source) {
405         case AudioSource.DEFAULT:
406             return "DEFAULT";
407         case AudioSource.MIC:
408             return "MIC";
409         case AudioSource.VOICE_UPLINK:
410             return "VOICE_UPLINK";
411         case AudioSource.VOICE_DOWNLINK:
412             return "VOICE_DOWNLINK";
413         case AudioSource.VOICE_CALL:
414             return "VOICE_CALL";
415         case AudioSource.CAMCORDER:
416             return "CAMCORDER";
417         case AudioSource.VOICE_RECOGNITION:
418             return "VOICE_RECOGNITION";
419         case AudioSource.VOICE_COMMUNICATION:
420             return "VOICE_COMMUNICATION";
421         case AudioSource.REMOTE_SUBMIX:
422             return "REMOTE_SUBMIX";
423         case AudioSource.UNPROCESSED:
424             return "UNPROCESSED";
425         case AudioSource.ECHO_REFERENCE:
426             return "ECHO_REFERENCE";
427         case AudioSource.VOICE_PERFORMANCE:
428             return "VOICE_PERFORMANCE";
429         case AudioSource.RADIO_TUNER:
430             return "RADIO_TUNER";
431         case AudioSource.HOTWORD:
432             return "HOTWORD";
433         case AudioSource.AUDIO_SOURCE_INVALID:
434             return "AUDIO_SOURCE_INVALID";
435         default:
436             return "unknown source " + source;
437         }
438     }
439 
440     /**
441      * Defines the video source. These constants are used with
442      * {@link MediaRecorder#setVideoSource(int)}.
443      */
444     public final class VideoSource {
445       /* Do not change these values without updating their counterparts
446        * in include/media/mediarecorder.h!
447        */
VideoSource()448         private VideoSource() {}
449         public static final int DEFAULT = 0;
450         /** Camera video source
451          * <p>
452          * Using the {@link android.hardware.Camera} API as video source.
453          * </p>
454          */
455         public static final int CAMERA = 1;
456         /** Surface video source
457          * <p>
458          * Using a Surface as video source.
459          * </p><p>
460          * This flag must be used when recording from an
461          * {@link android.hardware.camera2} API source.
462          * </p><p>
463          * When using this video source type, use {@link MediaRecorder#getSurface()}
464          * to retrieve the surface created by MediaRecorder.
465          */
466         public static final int SURFACE = 2;
467     }
468 
469     /**
470      * Defines the output format. These constants are used with
471      * {@link MediaRecorder#setOutputFormat(int)}.
472      */
473     public final class OutputFormat {
474       /* Do not change these values without updating their counterparts
475        * in include/media/mediarecorder.h!
476        */
OutputFormat()477         private OutputFormat() {}
478         public static final int DEFAULT = 0;
479         /** 3GPP media file format*/
480         public static final int THREE_GPP = 1;
481         /** MPEG4 media file format*/
482         public static final int MPEG_4 = 2;
483 
484         /** The following formats are audio only .aac or .amr formats */
485 
486         /**
487          * AMR NB file format
488          * @deprecated  Deprecated in favor of MediaRecorder.OutputFormat.AMR_NB
489          */
490         public static final int RAW_AMR = 3;
491 
492         /** AMR NB file format */
493         public static final int AMR_NB = 3;
494 
495         /** AMR WB file format */
496         public static final int AMR_WB = 4;
497 
498         /** @hide AAC ADIF file format */
499         public static final int AAC_ADIF = 5;
500 
501         /** AAC ADTS file format */
502         public static final int AAC_ADTS = 6;
503 
504         /** @hide Stream over a socket, limited to a single stream */
505         public static final int OUTPUT_FORMAT_RTP_AVP = 7;
506 
507         /** H.264/AAC data encapsulated in MPEG2/TS */
508         public static final int MPEG_2_TS = 8;
509 
510         /** VP8/VORBIS data in a WEBM container */
511         public static final int WEBM = 9;
512 
513         /** @hide HEIC data in a HEIF container */
514         public static final int HEIF = 10;
515 
516         /** Opus data in a Ogg container */
517         public static final int OGG = 11;
518     };
519 
520     /**
521      * Defines the audio encoding. These constants are used with
522      * {@link MediaRecorder#setAudioEncoder(int)}.
523      */
524     public final class AudioEncoder {
525       /* Do not change these values without updating their counterparts
526        * in include/media/mediarecorder.h!
527        */
AudioEncoder()528         private AudioEncoder() {}
529         public static final int DEFAULT = 0;
530         /** AMR (Narrowband) audio codec */
531         public static final int AMR_NB = 1;
532         /** AMR (Wideband) audio codec */
533         public static final int AMR_WB = 2;
534         /** AAC Low Complexity (AAC-LC) audio codec */
535         public static final int AAC = 3;
536         /** High Efficiency AAC (HE-AAC) audio codec */
537         public static final int HE_AAC = 4;
538         /** Enhanced Low Delay AAC (AAC-ELD) audio codec */
539         public static final int AAC_ELD = 5;
540         /** Ogg Vorbis audio codec (Support is optional) */
541         public static final int VORBIS = 6;
542         /** Opus audio codec */
543         public static final int OPUS = 7;
544     }
545 
546     /**
547      * Defines the video encoding. These constants are used with
548      * {@link MediaRecorder#setVideoEncoder(int)}.
549      */
550     public final class VideoEncoder {
551       /* Do not change these values without updating their counterparts
552        * in include/media/mediarecorder.h!
553        */
VideoEncoder()554         private VideoEncoder() {}
555         public static final int DEFAULT = 0;
556         public static final int H263 = 1;
557         public static final int H264 = 2;
558         public static final int MPEG_4_SP = 3;
559         public static final int VP8 = 4;
560         public static final int HEVC = 5;
561     }
562 
563     /**
564      * Sets the audio source to be used for recording. If this method is not
565      * called, the output file will not contain an audio track. The source needs
566      * to be specified before setting recording-parameters or encoders. Call
567      * this only before setOutputFormat().
568      *
569      * @param audioSource the audio source to use
570      * @throws IllegalStateException if it is called after setOutputFormat()
571      * @see android.media.MediaRecorder.AudioSource
572      */
setAudioSource(@ource int audioSource)573     public native void setAudioSource(@Source int audioSource)
574             throws IllegalStateException;
575 
576     /**
577      * Gets the maximum value for audio sources.
578      * @see android.media.MediaRecorder.AudioSource
579      */
getAudioSourceMax()580     public static final int getAudioSourceMax() {
581         return AudioSource.VOICE_PERFORMANCE;
582     }
583 
584     /**
585      * Sets the video source to be used for recording. If this method is not
586      * called, the output file will not contain an video track. The source needs
587      * to be specified before setting recording-parameters or encoders. Call
588      * this only before setOutputFormat().
589      *
590      * @param video_source the video source to use
591      * @throws IllegalStateException if it is called after setOutputFormat()
592      * @see android.media.MediaRecorder.VideoSource
593      */
setVideoSource(int video_source)594     public native void setVideoSource(int video_source)
595             throws IllegalStateException;
596 
597     /**
598      * Uses the settings from a CamcorderProfile object for recording. This method should
599      * be called after the video AND audio sources are set, and before setOutputFile().
600      * If a time lapse CamcorderProfile is used, audio related source or recording
601      * parameters are ignored.
602      *
603      * @param profile the CamcorderProfile to use
604      * @see android.media.CamcorderProfile
605      */
setProfile(CamcorderProfile profile)606     public void setProfile(CamcorderProfile profile) {
607         setOutputFormat(profile.fileFormat);
608         setVideoFrameRate(profile.videoFrameRate);
609         setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
610         setVideoEncodingBitRate(profile.videoBitRate);
611         setVideoEncoder(profile.videoCodec);
612         if (profile.quality >= CamcorderProfile.QUALITY_TIME_LAPSE_LOW &&
613              profile.quality <= CamcorderProfile.QUALITY_TIME_LAPSE_QVGA) {
614             // Nothing needs to be done. Call to setCaptureRate() enables
615             // time lapse video recording.
616         } else {
617             setAudioEncodingBitRate(profile.audioBitRate);
618             setAudioChannels(profile.audioChannels);
619             setAudioSamplingRate(profile.audioSampleRate);
620             setAudioEncoder(profile.audioCodec);
621         }
622     }
623 
624     /**
625      * Set video frame capture rate. This can be used to set a different video frame capture
626      * rate than the recorded video's playback rate. This method also sets the recording mode
627      * to time lapse. In time lapse video recording, only video is recorded. Audio related
628      * parameters are ignored when a time lapse recording session starts, if an application
629      * sets them.
630      *
631      * @param fps Rate at which frames should be captured in frames per second.
632      * The fps can go as low as desired. However the fastest fps will be limited by the hardware.
633      * For resolutions that can be captured by the video camera, the fastest fps can be computed using
634      * {@link android.hardware.Camera.Parameters#getPreviewFpsRange(int[])}. For higher
635      * resolutions the fastest fps may be more restrictive.
636      * Note that the recorder cannot guarantee that frames will be captured at the
637      * given rate due to camera/encoder limitations. However it tries to be as close as
638      * possible.
639      */
setCaptureRate(double fps)640     public void setCaptureRate(double fps) {
641         // Make sure that time lapse is enabled when this method is called.
642         setParameter("time-lapse-enable=1");
643         setParameter("time-lapse-fps=" + fps);
644     }
645 
646     /**
647      * Sets the orientation hint for output video playback.
648      * This method should be called before prepare(). This method will not
649      * trigger the source video frame to rotate during video recording, but to
650      * add a composition matrix containing the rotation angle in the output
651      * video if the output format is OutputFormat.THREE_GPP or
652      * OutputFormat.MPEG_4 so that a video player can choose the proper
653      * orientation for playback. Note that some video players may choose
654      * to ignore the compostion matrix in a video during playback.
655      *
656      * @param degrees the angle to be rotated clockwise in degrees.
657      * The supported angles are 0, 90, 180, and 270 degrees.
658      * @throws IllegalArgumentException if the angle is not supported.
659      *
660      */
setOrientationHint(int degrees)661     public void setOrientationHint(int degrees) {
662         if (degrees != 0   &&
663             degrees != 90  &&
664             degrees != 180 &&
665             degrees != 270) {
666             throw new IllegalArgumentException("Unsupported angle: " + degrees);
667         }
668         setParameter("video-param-rotation-angle-degrees=" + degrees);
669     }
670 
671     /**
672      * Set and store the geodata (latitude and longitude) in the output file.
673      * This method should be called before prepare(). The geodata is
674      * stored in udta box if the output format is OutputFormat.THREE_GPP
675      * or OutputFormat.MPEG_4, and is ignored for other output formats.
676      * The geodata is stored according to ISO-6709 standard.
677      *
678      * @param latitude latitude in degrees. Its value must be in the
679      * range [-90, 90].
680      * @param longitude longitude in degrees. Its value must be in the
681      * range [-180, 180].
682      *
683      * @throws IllegalArgumentException if the given latitude or
684      * longitude is out of range.
685      *
686      */
setLocation(float latitude, float longitude)687     public void setLocation(float latitude, float longitude) {
688         int latitudex10000  = (int) (latitude * 10000 + 0.5);
689         int longitudex10000 = (int) (longitude * 10000 + 0.5);
690 
691         if (latitudex10000 > 900000 || latitudex10000 < -900000) {
692             String msg = "Latitude: " + latitude + " out of range.";
693             throw new IllegalArgumentException(msg);
694         }
695         if (longitudex10000 > 1800000 || longitudex10000 < -1800000) {
696             String msg = "Longitude: " + longitude + " out of range";
697             throw new IllegalArgumentException(msg);
698         }
699 
700         setParameter("param-geotag-latitude=" + latitudex10000);
701         setParameter("param-geotag-longitude=" + longitudex10000);
702     }
703 
704     /**
705      * Sets the format of the output file produced during recording. Call this
706      * after setAudioSource()/setVideoSource() but before prepare().
707      *
708      * <p>It is recommended to always use 3GP format when using the H.263
709      * video encoder and AMR audio encoder. Using an MPEG-4 container format
710      * may confuse some desktop players.</p>
711      *
712      * @param output_format the output format to use. The output format
713      * needs to be specified before setting recording-parameters or encoders.
714      * @throws IllegalStateException if it is called after prepare() or before
715      * setAudioSource()/setVideoSource().
716      * @see android.media.MediaRecorder.OutputFormat
717      */
setOutputFormat(int output_format)718     public native void setOutputFormat(int output_format)
719             throws IllegalStateException;
720 
721     /**
722      * Sets the width and height of the video to be captured.  Must be called
723      * after setVideoSource(). Call this after setOutFormat() but before
724      * prepare().
725      *
726      * @param width the width of the video to be captured
727      * @param height the height of the video to be captured
728      * @throws IllegalStateException if it is called after
729      * prepare() or before setOutputFormat()
730      */
setVideoSize(int width, int height)731     public native void setVideoSize(int width, int height)
732             throws IllegalStateException;
733 
734     /**
735      * Sets the frame rate of the video to be captured.  Must be called
736      * after setVideoSource(). Call this after setOutFormat() but before
737      * prepare().
738      *
739      * @param rate the number of frames per second of video to capture
740      * @throws IllegalStateException if it is called after
741      * prepare() or before setOutputFormat().
742      *
743      * NOTE: On some devices that have auto-frame rate, this sets the
744      * maximum frame rate, not a constant frame rate. Actual frame rate
745      * will vary according to lighting conditions.
746      */
setVideoFrameRate(int rate)747     public native void setVideoFrameRate(int rate) throws IllegalStateException;
748 
749     /**
750      * Sets the maximum duration (in ms) of the recording session.
751      * Call this after setOutFormat() but before prepare().
752      * After recording reaches the specified duration, a notification
753      * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
754      * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
755      * and recording will be stopped. Stopping happens asynchronously, there
756      * is no guarantee that the recorder will have stopped by the time the
757      * listener is notified.
758      *
759      * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with
760      * {@link OutputFormat#MPEG_4}), it is recommended to set maximum duration that fits the use
761      * case. Setting a larger than required duration may result in a larger than needed output file
762      * because of space reserved for MOOV box expecting large movie data in this recording session.
763      *  Unused space of MOOV box is turned into FREE box in the output file.</p>
764      *
765      * @param max_duration_ms the maximum duration in ms (if zero or negative, disables the duration limit)
766      *
767      */
setMaxDuration(int max_duration_ms)768     public native void setMaxDuration(int max_duration_ms) throws IllegalArgumentException;
769 
770     /**
771      * Sets the maximum filesize (in bytes) of the recording session.
772      * Call this after setOutFormat() but before prepare().
773      * After recording reaches the specified filesize, a notification
774      * will be sent to the {@link android.media.MediaRecorder.OnInfoListener}
775      * with a "what" code of {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
776      * and recording will be stopped. Stopping happens asynchronously, there
777      * is no guarantee that the recorder will have stopped by the time the
778      * listener is notified.
779      *
780      * <p>When using MPEG-4 container ({@link #setOutputFormat(int)} with
781      * {@link OutputFormat#MPEG_4}), it is recommended to set maximum filesize that fits the use
782      * case. Setting a larger than required filesize may result in a larger than needed output file
783      * because of space reserved for MOOV box expecting large movie data in this recording session.
784      * Unused space of MOOV box is turned into FREE box in the output file.</p>
785      *
786      * @param max_filesize_bytes the maximum filesize in bytes (if zero or negative, disables the limit)
787      *
788      */
setMaxFileSize(long max_filesize_bytes)789     public native void setMaxFileSize(long max_filesize_bytes) throws IllegalArgumentException;
790 
791     /**
792      * Sets the audio encoder to be used for recording. If this method is not
793      * called, the output file will not contain an audio track. Call this after
794      * setOutputFormat() but before prepare().
795      *
796      * @param audio_encoder the audio encoder to use.
797      * @throws IllegalStateException if it is called before
798      * setOutputFormat() or after prepare().
799      * @see android.media.MediaRecorder.AudioEncoder
800      */
setAudioEncoder(int audio_encoder)801     public native void setAudioEncoder(int audio_encoder)
802             throws IllegalStateException;
803 
804     /**
805      * Sets the video encoder to be used for recording. If this method is not
806      * called, the output file will not contain an video track. Call this after
807      * setOutputFormat() and before prepare().
808      *
809      * @param video_encoder the video encoder to use.
810      * @throws IllegalStateException if it is called before
811      * setOutputFormat() or after prepare()
812      * @see android.media.MediaRecorder.VideoEncoder
813      */
setVideoEncoder(int video_encoder)814     public native void setVideoEncoder(int video_encoder)
815             throws IllegalStateException;
816 
817     /**
818      * Sets the audio sampling rate for recording. Call this method before prepare().
819      * Prepare() may perform additional checks on the parameter to make sure whether
820      * the specified audio sampling rate is applicable. The sampling rate really depends
821      * on the format for the audio recording, as well as the capabilities of the platform.
822      * For instance, the sampling rate supported by AAC audio coding standard ranges
823      * from 8 to 96 kHz, the sampling rate supported by AMRNB is 8kHz, and the sampling
824      * rate supported by AMRWB is 16kHz. Please consult with the related audio coding
825      * standard for the supported audio sampling rate.
826      *
827      * @param samplingRate the sampling rate for audio in samples per second.
828      */
setAudioSamplingRate(int samplingRate)829     public void setAudioSamplingRate(int samplingRate) {
830         if (samplingRate <= 0) {
831             throw new IllegalArgumentException("Audio sampling rate is not positive");
832         }
833         setParameter("audio-param-sampling-rate=" + samplingRate);
834     }
835 
836     /**
837      * Sets the number of audio channels for recording. Call this method before prepare().
838      * Prepare() may perform additional checks on the parameter to make sure whether the
839      * specified number of audio channels are applicable.
840      *
841      * @param numChannels the number of audio channels. Usually it is either 1 (mono) or 2
842      * (stereo).
843      */
setAudioChannels(int numChannels)844     public void setAudioChannels(int numChannels) {
845         if (numChannels <= 0) {
846             throw new IllegalArgumentException("Number of channels is not positive");
847         }
848         mChannelCount = numChannels;
849         setParameter("audio-param-number-of-channels=" + numChannels);
850     }
851 
852     /**
853      * Sets the audio encoding bit rate for recording. Call this method before prepare().
854      * Prepare() may perform additional checks on the parameter to make sure whether the
855      * specified bit rate is applicable, and sometimes the passed bitRate will be clipped
856      * internally to ensure the audio recording can proceed smoothly based on the
857      * capabilities of the platform.
858      *
859      * @param bitRate the audio encoding bit rate in bits per second.
860      */
setAudioEncodingBitRate(int bitRate)861     public void setAudioEncodingBitRate(int bitRate) {
862         if (bitRate <= 0) {
863             throw new IllegalArgumentException("Audio encoding bit rate is not positive");
864         }
865         setParameter("audio-param-encoding-bitrate=" + bitRate);
866     }
867 
868     /**
869      * Sets the video encoding bit rate for recording. Call this method before prepare().
870      * Prepare() may perform additional checks on the parameter to make sure whether the
871      * specified bit rate is applicable, and sometimes the passed bitRate will be
872      * clipped internally to ensure the video recording can proceed smoothly based on
873      * the capabilities of the platform.
874      *
875      * @param bitRate the video encoding bit rate in bits per second.
876      */
setVideoEncodingBitRate(int bitRate)877     public void setVideoEncodingBitRate(int bitRate) {
878         if (bitRate <= 0) {
879             throw new IllegalArgumentException("Video encoding bit rate is not positive");
880         }
881         setParameter("video-param-encoding-bitrate=" + bitRate);
882     }
883 
884     /**
885      * Sets the desired video encoding profile and level for recording. The profile and level
886      * must be valid for the video encoder set by {@link #setVideoEncoder}. This method can
887      * called before or after {@link #setVideoEncoder} but it must be called before {@link #prepare}.
888      * {@code prepare()} may perform additional checks on the parameter to make sure that the specified
889      * profile and level are applicable, and sometimes the passed profile or level will be
890      * discarded due to codec capablity or to ensure the video recording can proceed smoothly
891      * based on the capabilities of the platform. <br>Application can also use the
892      * {@link MediaCodecInfo.CodecCapabilities#profileLevels} to query applicable combination of profile
893      * and level for the corresponding format. Note that the requested profile/level may not be supported by
894      * the codec that is actually being used by this MediaRecorder instance.
895      * @param profile declared in {@link MediaCodecInfo.CodecProfileLevel}.
896      * @param level declared in {@link MediaCodecInfo.CodecProfileLevel}.
897      * @throws IllegalArgumentException when an invalid profile or level value is used.
898      */
setVideoEncodingProfileLevel(int profile, int level)899     public void setVideoEncodingProfileLevel(int profile, int level) {
900         if (profile <= 0)  {
901             throw new IllegalArgumentException("Video encoding profile is not positive");
902         }
903         if (level <= 0)  {
904             throw new IllegalArgumentException("Video encoding level is not positive");
905         }
906         setParameter("video-param-encoder-profile=" + profile);
907         setParameter("video-param-encoder-level=" + level);
908     }
909 
910     /**
911      * Currently not implemented. It does nothing.
912      * @deprecated Time lapse mode video recording using camera still image capture
913      * is not desirable, and will not be supported.
914      * @hide
915      */
setAuxiliaryOutputFile(FileDescriptor fd)916     public void setAuxiliaryOutputFile(FileDescriptor fd)
917     {
918         Log.w(TAG, "setAuxiliaryOutputFile(FileDescriptor) is no longer supported.");
919     }
920 
921     /**
922      * Currently not implemented. It does nothing.
923      * @deprecated Time lapse mode video recording using camera still image capture
924      * is not desirable, and will not be supported.
925      * @hide
926      */
setAuxiliaryOutputFile(String path)927     public void setAuxiliaryOutputFile(String path)
928     {
929         Log.w(TAG, "setAuxiliaryOutputFile(String) is no longer supported.");
930     }
931 
932     /**
933      * Pass in the file descriptor of the file to be written. Call this after
934      * setOutputFormat() but before prepare().
935      *
936      * @param fd an open file descriptor to be written into.
937      * @throws IllegalStateException if it is called before
938      * setOutputFormat() or after prepare()
939      */
setOutputFile(FileDescriptor fd)940     public void setOutputFile(FileDescriptor fd) throws IllegalStateException
941     {
942         mPath = null;
943         mFile = null;
944         mFd = fd;
945     }
946 
947     /**
948      * Pass in the file object to be written. Call this after setOutputFormat() but before prepare().
949      * File should be seekable. After setting the next output file, application should not use the
950      * file until {@link #stop}. Application is responsible for cleaning up unused files after
951      * {@link #stop} is called.
952      *
953      * @param file the file object to be written into.
954      */
setOutputFile(File file)955     public void setOutputFile(File file)
956     {
957         mPath = null;
958         mFd = null;
959         mFile = file;
960     }
961 
962     /**
963      * Sets the next output file descriptor to be used when the maximum filesize is reached
964      * on the prior output {@link #setOutputFile} or {@link #setNextOutputFile}). File descriptor
965      * must be seekable and writable. After setting the next output file, application should not
966      * use the file referenced by this file descriptor until {@link #stop}. It is the application's
967      * responsibility to close the file descriptor. It is safe to do so as soon as this call returns.
968      * Application must call this after receiving on the
969      * {@link android.media.MediaRecorder.OnInfoListener} a "what" code of
970      * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving a "what" code of
971      * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used until switching to
972      * that output. Application will receive{@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED}
973      * when the next output file is used. Application will not be able to set a new output file if
974      * the previous one has not been used. Application is responsible for cleaning up unused files
975      * after {@link #stop} is called.
976      *
977      * @param fd an open file descriptor to be written into.
978      * @throws IllegalStateException if it is called before prepare().
979      * @throws IOException if setNextOutputFile fails otherwise.
980      */
setNextOutputFile(FileDescriptor fd)981     public void setNextOutputFile(FileDescriptor fd) throws IOException
982     {
983         _setNextOutputFile(fd);
984     }
985 
986     /**
987      * Sets the path of the output file to be produced. Call this after
988      * setOutputFormat() but before prepare().
989      *
990      * @param path The pathname to use.
991      * @throws IllegalStateException if it is called before
992      * setOutputFormat() or after prepare()
993      */
setOutputFile(String path)994     public void setOutputFile(String path) throws IllegalStateException
995     {
996         mFd = null;
997         mFile = null;
998         mPath = path;
999     }
1000 
1001     /**
1002      * Sets the next output file to be used when the maximum filesize is reached on the prior
1003      * output {@link #setOutputFile} or {@link #setNextOutputFile}). File should be seekable.
1004      * After setting the next output file, application should not use the file until {@link #stop}.
1005      * Application must call this after receiving on the
1006      * {@link android.media.MediaRecorder.OnInfoListener} a "what" code of
1007      * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING} and before receiving a "what" code of
1008      * {@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}. The file is not used until switching to
1009      * that output. Application will receive {@link #MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED}
1010      * when the next output file is used. Application will not be able to set a new output file if
1011      * the previous one has not been used. Application is responsible for cleaning up unused files
1012      * after {@link #stop} is called.
1013      *
1014      * @param  file The file to use.
1015      * @throws IllegalStateException if it is called before prepare().
1016      * @throws IOException if setNextOutputFile fails otherwise.
1017      */
setNextOutputFile(File file)1018     public void setNextOutputFile(File file) throws IOException
1019     {
1020         RandomAccessFile f = new RandomAccessFile(file, "rw");
1021         try {
1022             _setNextOutputFile(f.getFD());
1023         } finally {
1024             f.close();
1025         }
1026     }
1027 
1028     // native implementation
_setOutputFile(FileDescriptor fd)1029     private native void _setOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
_setNextOutputFile(FileDescriptor fd)1030     private native void _setNextOutputFile(FileDescriptor fd) throws IllegalStateException, IOException;
1031     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
_prepare()1032     private native void _prepare() throws IllegalStateException, IOException;
1033 
1034     /**
1035      * Prepares the recorder to begin capturing and encoding data. This method
1036      * must be called after setting up the desired audio and video sources,
1037      * encoders, file format, etc., but before start().
1038      *
1039      * @throws IllegalStateException if it is called after
1040      * start() or before setOutputFormat().
1041      * @throws IOException if prepare fails otherwise.
1042      */
prepare()1043     public void prepare() throws IllegalStateException, IOException
1044     {
1045         if (mPath != null) {
1046             RandomAccessFile file = new RandomAccessFile(mPath, "rw");
1047             try {
1048                 _setOutputFile(file.getFD());
1049             } finally {
1050                 file.close();
1051             }
1052         } else if (mFd != null) {
1053             _setOutputFile(mFd);
1054         } else if (mFile != null) {
1055             RandomAccessFile file = new RandomAccessFile(mFile, "rw");
1056             try {
1057                 _setOutputFile(file.getFD());
1058             } finally {
1059                 file.close();
1060             }
1061         } else {
1062             throw new IOException("No valid output file");
1063         }
1064 
1065         _prepare();
1066     }
1067 
1068     /**
1069      * Begins capturing and encoding data to the file specified with
1070      * setOutputFile(). Call this after prepare().
1071      *
1072      * <p>Since API level 13, if applications set a camera via
1073      * {@link #setCamera(Camera)}, the apps can use the camera after this method
1074      * call. The apps do not need to lock the camera again. However, if this
1075      * method fails, the apps should still lock the camera back. The apps should
1076      * not start another recording session during recording.
1077      *
1078      * @throws IllegalStateException if it is called before
1079      * prepare() or when the camera is already in use by another app.
1080      */
start()1081     public native void start() throws IllegalStateException;
1082 
1083     /**
1084      * Stops recording. Call this after start(). Once recording is stopped,
1085      * you will have to configure it again as if it has just been constructed.
1086      * Note that a RuntimeException is intentionally thrown to the
1087      * application, if no valid audio/video data has been received when stop()
1088      * is called. This happens if stop() is called immediately after
1089      * start(). The failure lets the application take action accordingly to
1090      * clean up the output file (delete the output file, for instance), since
1091      * the output file is not properly constructed when this happens.
1092      *
1093      * @throws IllegalStateException if it is called before start()
1094      */
stop()1095     public native void stop() throws IllegalStateException;
1096 
1097     /**
1098      * Pauses recording. Call this after start(). You may resume recording
1099      * with resume() without reconfiguration, as opposed to stop(). It does
1100      * nothing if the recording is already paused.
1101      *
1102      * When the recording is paused and resumed, the resulting output would
1103      * be as if nothing happend during paused period, immediately switching
1104      * to the resumed scene.
1105      *
1106      * @throws IllegalStateException if it is called before start() or after
1107      * stop()
1108      */
pause()1109     public native void pause() throws IllegalStateException;
1110 
1111     /**
1112      * Resumes recording. Call this after start(). It does nothing if the
1113      * recording is not paused.
1114      *
1115      * @throws IllegalStateException if it is called before start() or after
1116      * stop()
1117      * @see android.media.MediaRecorder#pause
1118      */
resume()1119     public native void resume() throws IllegalStateException;
1120 
1121     /**
1122      * Restarts the MediaRecorder to its idle state. After calling
1123      * this method, you will have to configure it again as if it had just been
1124      * constructed.
1125      */
reset()1126     public void reset() {
1127         native_reset();
1128 
1129         // make sure none of the listeners get called anymore
1130         mEventHandler.removeCallbacksAndMessages(null);
1131     }
1132 
1133     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_reset()1134     private native void native_reset();
1135 
1136     /**
1137      * Returns the maximum absolute amplitude that was sampled since the last
1138      * call to this method. Call this only after the setAudioSource().
1139      *
1140      * @return the maximum absolute amplitude measured since the last call, or
1141      * 0 when called for the first time
1142      * @throws IllegalStateException if it is called before
1143      * the audio source has been set.
1144      */
getMaxAmplitude()1145     public native int getMaxAmplitude() throws IllegalStateException;
1146 
1147     /* Do not change this value without updating its counterpart
1148      * in include/media/mediarecorder.h or mediaplayer.h!
1149      */
1150     /** Unspecified media recorder error.
1151      * @see android.media.MediaRecorder.OnErrorListener
1152      */
1153     public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1;
1154     /** Media server died. In this case, the application must release the
1155      * MediaRecorder object and instantiate a new one.
1156      * @see android.media.MediaRecorder.OnErrorListener
1157      */
1158     public static final int MEDIA_ERROR_SERVER_DIED = 100;
1159 
1160     /**
1161      * Interface definition for a callback to be invoked when an error
1162      * occurs while recording.
1163      */
1164     public interface OnErrorListener
1165     {
1166         /**
1167          * Called when an error occurs while recording.
1168          *
1169          * @param mr the MediaRecorder that encountered the error
1170          * @param what    the type of error that has occurred:
1171          * <ul>
1172          * <li>{@link #MEDIA_RECORDER_ERROR_UNKNOWN}
1173          * <li>{@link #MEDIA_ERROR_SERVER_DIED}
1174          * </ul>
1175          * @param extra   an extra code, specific to the error type
1176          */
onError(MediaRecorder mr, int what, int extra)1177         void onError(MediaRecorder mr, int what, int extra);
1178     }
1179 
1180     /**
1181      * Register a callback to be invoked when an error occurs while
1182      * recording.
1183      *
1184      * @param l the callback that will be run
1185      */
setOnErrorListener(OnErrorListener l)1186     public void setOnErrorListener(OnErrorListener l)
1187     {
1188         mOnErrorListener = l;
1189     }
1190 
1191     /* Do not change these values without updating their counterparts
1192      * in include/media/mediarecorder.h!
1193      */
1194     /** Unspecified media recorder info.
1195      * @see android.media.MediaRecorder.OnInfoListener
1196      */
1197     public static final int MEDIA_RECORDER_INFO_UNKNOWN              = 1;
1198     /** A maximum duration had been setup and has now been reached.
1199      * @see android.media.MediaRecorder.OnInfoListener
1200      */
1201     public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800;
1202     /** A maximum filesize had been setup and has now been reached.
1203      * Note: This event will not be sent if application already set
1204      * next output file through {@link #setNextOutputFile}.
1205      * @see android.media.MediaRecorder.OnInfoListener
1206      */
1207     public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED = 801;
1208     /** A maximum filesize had been setup and current recorded file size
1209      * has reached 90% of the limit. This is sent once per file upon
1210      * reaching/passing the 90% limit. To continue the recording, applicaiton
1211      * should use {@link #setNextOutputFile} to set the next output file.
1212      * Otherwise, recording will stop when reaching maximum file size.
1213      * @see android.media.MediaRecorder.OnInfoListener
1214      */
1215     public static final int MEDIA_RECORDER_INFO_MAX_FILESIZE_APPROACHING = 802;
1216     /** A maximum filesize had been reached and MediaRecorder has switched
1217      * output to a new file set by application {@link #setNextOutputFile}.
1218      * For best practice, application should use this event to keep track
1219      * of whether the file previously set has been used or not.
1220      * @see android.media.MediaRecorder.OnInfoListener
1221      */
1222     public static final int MEDIA_RECORDER_INFO_NEXT_OUTPUT_FILE_STARTED = 803;
1223 
1224     /** informational events for individual tracks, for testing purpose.
1225      * The track informational event usually contains two parts in the ext1
1226      * arg of the onInfo() callback: bit 31-28 contains the track id; and
1227      * the rest of the 28 bits contains the informational event defined here.
1228      * For example, ext1 = (1 << 28 | MEDIA_RECORDER_TRACK_INFO_TYPE) if the
1229      * track id is 1 for informational event MEDIA_RECORDER_TRACK_INFO_TYPE;
1230      * while ext1 = (0 << 28 | MEDIA_RECORDER_TRACK_INFO_TYPE) if the track
1231      * id is 0 for informational event MEDIA_RECORDER_TRACK_INFO_TYPE. The
1232      * application should extract the track id and the type of informational
1233      * event from ext1, accordingly.
1234      *
1235      * FIXME:
1236      * Please update the comment for onInfo also when these
1237      * events are unhidden so that application knows how to extract the track
1238      * id and the informational event type from onInfo callback.
1239      *
1240      * {@hide}
1241      */
1242     public static final int MEDIA_RECORDER_TRACK_INFO_LIST_START        = 1000;
1243     /** Signal the completion of the track for the recording session.
1244      * {@hide}
1245      */
1246     public static final int MEDIA_RECORDER_TRACK_INFO_COMPLETION_STATUS = 1000;
1247     /** Indicate the recording progress in time (ms) during recording.
1248      * {@hide}
1249      */
1250     public static final int MEDIA_RECORDER_TRACK_INFO_PROGRESS_IN_TIME  = 1001;
1251     /** Indicate the track type: 0 for Audio and 1 for Video.
1252      * {@hide}
1253      */
1254     public static final int MEDIA_RECORDER_TRACK_INFO_TYPE              = 1002;
1255     /** Provide the track duration information.
1256      * {@hide}
1257      */
1258     public static final int MEDIA_RECORDER_TRACK_INFO_DURATION_MS       = 1003;
1259     /** Provide the max chunk duration in time (ms) for the given track.
1260      * {@hide}
1261      */
1262     public static final int MEDIA_RECORDER_TRACK_INFO_MAX_CHUNK_DUR_MS  = 1004;
1263     /** Provide the total number of recordd frames.
1264      * {@hide}
1265      */
1266     public static final int MEDIA_RECORDER_TRACK_INFO_ENCODED_FRAMES    = 1005;
1267     /** Provide the max spacing between neighboring chunks for the given track.
1268      * {@hide}
1269      */
1270     public static final int MEDIA_RECORDER_TRACK_INTER_CHUNK_TIME_MS    = 1006;
1271     /** Provide the elapsed time measuring from the start of the recording
1272      * till the first output frame of the given track is received, excluding
1273      * any intentional start time offset of a recording session for the
1274      * purpose of eliminating the recording sound in the recorded file.
1275      * {@hide}
1276      */
1277     public static final int MEDIA_RECORDER_TRACK_INFO_INITIAL_DELAY_MS  = 1007;
1278     /** Provide the start time difference (delay) betweeen this track and
1279      * the start of the movie.
1280      * {@hide}
1281      */
1282     public static final int MEDIA_RECORDER_TRACK_INFO_START_OFFSET_MS   = 1008;
1283     /** Provide the total number of data (in kilo-bytes) encoded.
1284      * {@hide}
1285      */
1286     public static final int MEDIA_RECORDER_TRACK_INFO_DATA_KBYTES       = 1009;
1287     /**
1288      * {@hide}
1289      */
1290     public static final int MEDIA_RECORDER_TRACK_INFO_LIST_END          = 2000;
1291 
1292 
1293     /**
1294      * Interface definition of a callback to be invoked to communicate some
1295      * info and/or warning about the recording.
1296      */
1297     public interface OnInfoListener
1298     {
1299         /**
1300          * Called to indicate an info or a warning during recording.
1301          *
1302          * @param mr   the MediaRecorder the info pertains to
1303          * @param what the type of info or warning that has occurred
1304          * <ul>
1305          * <li>{@link #MEDIA_RECORDER_INFO_UNKNOWN}
1306          * <li>{@link #MEDIA_RECORDER_INFO_MAX_DURATION_REACHED}
1307          * <li>{@link #MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED}
1308          * </ul>
1309          * @param extra   an extra code, specific to the info type
1310          */
onInfo(MediaRecorder mr, int what, int extra)1311         void onInfo(MediaRecorder mr, int what, int extra);
1312     }
1313 
1314     /**
1315      * Register a callback to be invoked when an informational event occurs while
1316      * recording.
1317      *
1318      * @param listener the callback that will be run
1319      */
setOnInfoListener(OnInfoListener listener)1320     public void setOnInfoListener(OnInfoListener listener)
1321     {
1322         mOnInfoListener = listener;
1323     }
1324 
1325     private class EventHandler extends Handler
1326     {
1327         private MediaRecorder mMediaRecorder;
1328 
EventHandler(MediaRecorder mr, Looper looper)1329         public EventHandler(MediaRecorder mr, Looper looper) {
1330             super(looper);
1331             mMediaRecorder = mr;
1332         }
1333 
1334         /* Do not change these values without updating their counterparts
1335          * in include/media/mediarecorder.h!
1336          */
1337         private static final int MEDIA_RECORDER_EVENT_LIST_START = 1;
1338         private static final int MEDIA_RECORDER_EVENT_ERROR      = 1;
1339         private static final int MEDIA_RECORDER_EVENT_INFO       = 2;
1340         private static final int MEDIA_RECORDER_EVENT_LIST_END   = 99;
1341 
1342         /* Events related to individual tracks */
1343         private static final int MEDIA_RECORDER_TRACK_EVENT_LIST_START = 100;
1344         private static final int MEDIA_RECORDER_TRACK_EVENT_ERROR      = 100;
1345         private static final int MEDIA_RECORDER_TRACK_EVENT_INFO       = 101;
1346         private static final int MEDIA_RECORDER_TRACK_EVENT_LIST_END   = 1000;
1347 
1348         private static final int MEDIA_RECORDER_AUDIO_ROUTING_CHANGED  = 10000;
1349 
1350         @Override
handleMessage(Message msg)1351         public void handleMessage(Message msg) {
1352             if (mMediaRecorder.mNativeContext == 0) {
1353                 Log.w(TAG, "mediarecorder went away with unhandled events");
1354                 return;
1355             }
1356             switch(msg.what) {
1357             case MEDIA_RECORDER_EVENT_ERROR:
1358             case MEDIA_RECORDER_TRACK_EVENT_ERROR:
1359                 if (mOnErrorListener != null)
1360                     mOnErrorListener.onError(mMediaRecorder, msg.arg1, msg.arg2);
1361 
1362                 return;
1363 
1364             case MEDIA_RECORDER_EVENT_INFO:
1365             case MEDIA_RECORDER_TRACK_EVENT_INFO:
1366                 if (mOnInfoListener != null)
1367                     mOnInfoListener.onInfo(mMediaRecorder, msg.arg1, msg.arg2);
1368 
1369                 return;
1370 
1371             case MEDIA_RECORDER_AUDIO_ROUTING_CHANGED:
1372                 AudioManager.resetAudioPortGeneration();
1373                 synchronized (mRoutingChangeListeners) {
1374                     for (NativeRoutingEventHandlerDelegate delegate
1375                             : mRoutingChangeListeners.values()) {
1376                         delegate.notifyClient();
1377                     }
1378                 }
1379                 return;
1380 
1381             default:
1382                 Log.e(TAG, "Unknown message type " + msg.what);
1383                 return;
1384             }
1385         }
1386     }
1387 
1388     //--------------------------------------------------------------------------
1389     // Explicit Routing
1390     //--------------------
1391     private AudioDeviceInfo mPreferredDevice = null;
1392 
1393     /**
1394      * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
1395      * the input from this MediaRecorder.
1396      * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio source.
1397      *  If deviceInfo is null, default routing is restored.
1398      * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
1399      * does not correspond to a valid audio input device.
1400      */
1401     @Override
setPreferredDevice(AudioDeviceInfo deviceInfo)1402     public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
1403         if (deviceInfo != null && !deviceInfo.isSource()) {
1404             return false;
1405         }
1406         int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
1407         boolean status = native_setInputDevice(preferredDeviceId);
1408         if (status == true) {
1409             synchronized (this) {
1410                 mPreferredDevice = deviceInfo;
1411             }
1412         }
1413         return status;
1414     }
1415 
1416     /**
1417      * Returns the selected input device specified by {@link #setPreferredDevice}. Note that this
1418      * is not guaranteed to correspond to the actual device being used for recording.
1419      */
1420     @Override
getPreferredDevice()1421     public AudioDeviceInfo getPreferredDevice() {
1422         synchronized (this) {
1423             return mPreferredDevice;
1424         }
1425     }
1426 
1427     /**
1428      * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder
1429      * Note: The query is only valid if the MediaRecorder is currently recording.
1430      * If the recorder is not recording, the returned device can be null or correspond to previously
1431      * selected device when the recorder was last active.
1432      */
1433     @Override
getRoutedDevice()1434     public AudioDeviceInfo getRoutedDevice() {
1435         int deviceId = native_getRoutedDeviceId();
1436         if (deviceId == 0) {
1437             return null;
1438         }
1439         AudioDeviceInfo[] devices =
1440                 AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
1441         for (int i = 0; i < devices.length; i++) {
1442             if (devices[i].getId() == deviceId) {
1443                 return devices[i];
1444             }
1445         }
1446         return null;
1447     }
1448 
1449     /*
1450      * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
1451      */
1452     @GuardedBy("mRoutingChangeListeners")
enableNativeRoutingCallbacksLocked(boolean enabled)1453     private void enableNativeRoutingCallbacksLocked(boolean enabled) {
1454         if (mRoutingChangeListeners.size() == 0) {
1455             native_enableDeviceCallback(enabled);
1456         }
1457     }
1458 
1459     /**
1460      * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
1461      * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
1462      * by an app to receive (re)routing notifications.
1463      */
1464     @GuardedBy("mRoutingChangeListeners")
1465     private ArrayMap<AudioRouting.OnRoutingChangedListener,
1466             NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
1467 
1468     /**
1469      * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
1470      * changes on this MediaRecorder.
1471      * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
1472      * notifications of rerouting events.
1473      * @param handler  Specifies the {@link Handler} object for the thread on which to execute
1474      * the callback. If <code>null</code>, the handler on the main looper will be used.
1475      */
1476     @Override
addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener, Handler handler)1477     public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
1478                                             Handler handler) {
1479         synchronized (mRoutingChangeListeners) {
1480             if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
1481                 enableNativeRoutingCallbacksLocked(true);
1482                 mRoutingChangeListeners.put(
1483                         listener, new NativeRoutingEventHandlerDelegate(this, listener,
1484                                 handler != null ? handler : mEventHandler));
1485             }
1486         }
1487     }
1488 
1489     /**
1490      * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
1491      * to receive rerouting notifications.
1492      * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
1493      * to remove.
1494      */
1495     @Override
removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener)1496     public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
1497         synchronized (mRoutingChangeListeners) {
1498             if (mRoutingChangeListeners.containsKey(listener)) {
1499                 mRoutingChangeListeners.remove(listener);
1500                 enableNativeRoutingCallbacksLocked(false);
1501             }
1502         }
1503     }
1504 
native_setInputDevice(int deviceId)1505     private native final boolean native_setInputDevice(int deviceId);
native_getRoutedDeviceId()1506     private native final int native_getRoutedDeviceId();
native_enableDeviceCallback(boolean enabled)1507     private native final void native_enableDeviceCallback(boolean enabled);
1508 
1509     //--------------------------------------------------------------------------
1510     // Microphone information
1511     //--------------------
1512     /**
1513      * Return A lists of {@link MicrophoneInfo} representing the active microphones.
1514      * By querying channel mapping for each active microphone, developer can know how
1515      * the microphone is used by each channels or a capture stream.
1516      *
1517      * @return a lists of {@link MicrophoneInfo} representing the active microphones
1518      * @throws IOException if an error occurs
1519      */
getActiveMicrophones()1520     public List<MicrophoneInfo> getActiveMicrophones() throws IOException {
1521         ArrayList<MicrophoneInfo> activeMicrophones = new ArrayList<>();
1522         int status = native_getActiveMicrophones(activeMicrophones);
1523         if (status != AudioManager.SUCCESS) {
1524             if (status != AudioManager.ERROR_INVALID_OPERATION) {
1525                 Log.e(TAG, "getActiveMicrophones failed:" + status);
1526             }
1527             Log.i(TAG, "getActiveMicrophones failed, fallback on routed device info");
1528         }
1529         AudioManager.setPortIdForMicrophones(activeMicrophones);
1530 
1531         // Use routed device when there is not information returned by hal.
1532         if (activeMicrophones.size() == 0) {
1533             AudioDeviceInfo device = getRoutedDevice();
1534             if (device != null) {
1535                 MicrophoneInfo microphone = AudioManager.microphoneInfoFromAudioDeviceInfo(device);
1536                 ArrayList<Pair<Integer, Integer>> channelMapping = new ArrayList<>();
1537                 for (int i = 0; i < mChannelCount; i++) {
1538                     channelMapping.add(new Pair(i, MicrophoneInfo.CHANNEL_MAPPING_DIRECT));
1539                 }
1540                 microphone.setChannelMapping(channelMapping);
1541                 activeMicrophones.add(microphone);
1542             }
1543         }
1544         return activeMicrophones;
1545     }
1546 
native_getActiveMicrophones( ArrayList<MicrophoneInfo> activeMicrophones)1547     private native final int native_getActiveMicrophones(
1548             ArrayList<MicrophoneInfo> activeMicrophones);
1549 
1550     //--------------------------------------------------------------------------
1551     // MicrophoneDirection
1552     //--------------------
1553     /**
1554      * Specifies the logical microphone (for processing).
1555      *
1556      * @param direction Direction constant.
1557      * @return true if sucessful.
1558      */
setPreferredMicrophoneDirection(@irectionMode int direction)1559     public boolean setPreferredMicrophoneDirection(@DirectionMode int direction) {
1560         return native_setPreferredMicrophoneDirection(direction) == 0;
1561     }
1562 
1563     /**
1564      * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
1565      * (for processing). The selected microphone is determined by the use-case for the stream.
1566      *
1567      * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
1568      * though 0 (no zoom) to 1 (maximum zoom).
1569      * @return true if sucessful.
1570      */
setPreferredMicrophoneFieldDimension( @loatRangefrom = -1.0, to = 1.0) float zoom)1571     public boolean setPreferredMicrophoneFieldDimension(
1572                             @FloatRange(from = -1.0, to = 1.0) float zoom) {
1573         Preconditions.checkArgument(
1574                 zoom >= -1 && zoom <= 1, "Argument must fall between -1 & 1 (inclusive)");
1575         return native_setPreferredMicrophoneFieldDimension(zoom) == 0;
1576     }
1577 
native_setPreferredMicrophoneDirection(int direction)1578     private native int native_setPreferredMicrophoneDirection(int direction);
native_setPreferredMicrophoneFieldDimension(float zoom)1579     private native int native_setPreferredMicrophoneFieldDimension(float zoom);
1580 
1581     //--------------------------------------------------------------------------
1582     // Implementation of AudioRecordingMonitor interface
1583     //--------------------
1584 
1585     AudioRecordingMonitorImpl mRecordingInfoImpl =
1586             new AudioRecordingMonitorImpl((AudioRecordingMonitorClient) this);
1587 
1588     /**
1589      * Register a callback to be notified of audio capture changes via a
1590      * {@link AudioManager.AudioRecordingCallback}. A callback is received when the capture path
1591      * configuration changes (pre-processing, format, sampling rate...) or capture is
1592      * silenced/unsilenced by the system.
1593      * @param executor {@link Executor} to handle the callbacks.
1594      * @param cb non-null callback to register
1595      */
registerAudioRecordingCallback(@onNull @allbackExecutor Executor executor, @NonNull AudioManager.AudioRecordingCallback cb)1596     public void registerAudioRecordingCallback(@NonNull @CallbackExecutor Executor executor,
1597             @NonNull AudioManager.AudioRecordingCallback cb) {
1598         mRecordingInfoImpl.registerAudioRecordingCallback(executor, cb);
1599     }
1600 
1601     /**
1602      * Unregister an audio recording callback previously registered with
1603      * {@link #registerAudioRecordingCallback(Executor, AudioManager.AudioRecordingCallback)}.
1604      * @param cb non-null callback to unregister
1605      */
unregisterAudioRecordingCallback(@onNull AudioManager.AudioRecordingCallback cb)1606     public void unregisterAudioRecordingCallback(@NonNull AudioManager.AudioRecordingCallback cb) {
1607         mRecordingInfoImpl.unregisterAudioRecordingCallback(cb);
1608     }
1609 
1610     /**
1611      * Returns the current active audio recording for this audio recorder.
1612      * @return a valid {@link AudioRecordingConfiguration} if this recorder is active
1613      * or null otherwise.
1614      * @see AudioRecordingConfiguration
1615      */
getActiveRecordingConfiguration()1616     public @Nullable AudioRecordingConfiguration getActiveRecordingConfiguration() {
1617         return mRecordingInfoImpl.getActiveRecordingConfiguration();
1618     }
1619 
1620     //---------------------------------------------------------
1621     // Implementation of AudioRecordingMonitorClient interface
1622     //--------------------
1623     /**
1624      * @hide
1625      */
getPortId()1626     public int getPortId() {
1627         return native_getPortId();
1628     }
1629 
native_getPortId()1630     private native int native_getPortId();
1631 
1632     /**
1633      * Called from native code when an interesting event happens.  This method
1634      * just uses the EventHandler system to post the event back to the main app thread.
1635      * We use a weak reference to the original MediaRecorder object so that the native
1636      * code is safe from the object disappearing from underneath it.  (This is
1637      * the cookie passed to native_setup().)
1638      */
postEventFromNative(Object mediarecorder_ref, int what, int arg1, int arg2, Object obj)1639     private static void postEventFromNative(Object mediarecorder_ref,
1640                                             int what, int arg1, int arg2, Object obj)
1641     {
1642         MediaRecorder mr = (MediaRecorder)((WeakReference)mediarecorder_ref).get();
1643         if (mr == null) {
1644             return;
1645         }
1646 
1647         if (mr.mEventHandler != null) {
1648             Message m = mr.mEventHandler.obtainMessage(what, arg1, arg2, obj);
1649             mr.mEventHandler.sendMessage(m);
1650         }
1651     }
1652 
1653     /**
1654      * Releases resources associated with this MediaRecorder object.
1655      * It is good practice to call this method when you're done
1656      * using the MediaRecorder. In particular, whenever an Activity
1657      * of an application is paused (its onPause() method is called),
1658      * or stopped (its onStop() method is called), this method should be
1659      * invoked to release the MediaRecorder object, unless the application
1660      * has a special need to keep the object around. In addition to
1661      * unnecessary resources (such as memory and instances of codecs)
1662      * being held, failure to call this method immediately if a
1663      * MediaRecorder object is no longer needed may also lead to
1664      * continuous battery consumption for mobile devices, and recording
1665      * failure for other applications if no multiple instances of the
1666      * same codec are supported on a device. Even if multiple instances
1667      * of the same codec are supported, some performance degradation
1668      * may be expected when unnecessary multiple instances are used
1669      * at the same time.
1670      */
release()1671     public native void release();
1672 
1673     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_init()1674     private static native final void native_init();
1675 
1676     @UnsupportedAppUsage
native_setup(Object mediarecorder_this, String clientName, String opPackageName)1677     private native final void native_setup(Object mediarecorder_this,
1678             String clientName, String opPackageName) throws IllegalStateException;
1679 
1680     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
native_finalize()1681     private native final void native_finalize();
1682 
1683     @UnsupportedAppUsage
setParameter(String nameValuePair)1684     private native void setParameter(String nameValuePair);
1685 
1686     /**
1687      *  Return Metrics data about the current Mediarecorder instance.
1688      *
1689      * @return a {@link PersistableBundle} containing the set of attributes and values
1690      * available for the media being generated by this instance of
1691      * MediaRecorder.
1692      * The attributes are descibed in {@link MetricsConstants}.
1693      *
1694      *  Additional vendor-specific fields may also be present in
1695      *  the return value.
1696      */
getMetrics()1697     public PersistableBundle getMetrics() {
1698         PersistableBundle bundle = native_getMetrics();
1699         return bundle;
1700     }
1701 
native_getMetrics()1702     private native PersistableBundle native_getMetrics();
1703 
1704     @Override
finalize()1705     protected void finalize() { native_finalize(); }
1706 
1707     public final static class MetricsConstants
1708     {
MetricsConstants()1709         private MetricsConstants() {}
1710 
1711         /**
1712          * Key to extract the audio bitrate
1713          * from the {@link MediaRecorder#getMetrics} return.
1714          * The value is an integer.
1715          */
1716         public static final String AUDIO_BITRATE = "android.media.mediarecorder.audio-bitrate";
1717 
1718         /**
1719          * Key to extract the number of audio channels
1720          * from the {@link MediaRecorder#getMetrics} return.
1721          * The value is an integer.
1722          */
1723         public static final String AUDIO_CHANNELS = "android.media.mediarecorder.audio-channels";
1724 
1725         /**
1726          * Key to extract the audio samplerate
1727          * from the {@link MediaRecorder#getMetrics} return.
1728          * The value is an integer.
1729          */
1730         public static final String AUDIO_SAMPLERATE = "android.media.mediarecorder.audio-samplerate";
1731 
1732         /**
1733          * Key to extract the audio timescale
1734          * from the {@link MediaRecorder#getMetrics} return.
1735          * The value is an integer.
1736          */
1737         public static final String AUDIO_TIMESCALE = "android.media.mediarecorder.audio-timescale";
1738 
1739         /**
1740          * Key to extract the video capture frame rate
1741          * from the {@link MediaRecorder#getMetrics} return.
1742          * The value is a double.
1743          */
1744         public static final String CAPTURE_FPS = "android.media.mediarecorder.capture-fps";
1745 
1746         /**
1747          * Key to extract the video capture framerate enable value
1748          * from the {@link MediaRecorder#getMetrics} return.
1749          * The value is an integer.
1750          */
1751         public static final String CAPTURE_FPS_ENABLE = "android.media.mediarecorder.capture-fpsenable";
1752 
1753         /**
1754          * Key to extract the intended playback frame rate
1755          * from the {@link MediaRecorder#getMetrics} return.
1756          * The value is an integer.
1757          */
1758         public static final String FRAMERATE = "android.media.mediarecorder.frame-rate";
1759 
1760         /**
1761          * Key to extract the height (in pixels) of the captured video
1762          * from the {@link MediaRecorder#getMetrics} return.
1763          * The value is an integer.
1764          */
1765         public static final String HEIGHT = "android.media.mediarecorder.height";
1766 
1767         /**
1768          * Key to extract the recorded movies time units
1769          * from the {@link MediaRecorder#getMetrics} return.
1770          * The value is an integer.
1771          * A value of 1000 indicates that the movie's timing is in milliseconds.
1772          */
1773         public static final String MOVIE_TIMESCALE = "android.media.mediarecorder.movie-timescale";
1774 
1775         /**
1776          * Key to extract the rotation (in degrees) to properly orient the video
1777          * from the {@link MediaRecorder#getMetrics} return.
1778          * The value is an integer.
1779          */
1780         public static final String ROTATION = "android.media.mediarecorder.rotation";
1781 
1782         /**
1783          * Key to extract the video bitrate from being used
1784          * from the {@link MediaRecorder#getMetrics} return.
1785          * The value is an integer.
1786          */
1787         public static final String VIDEO_BITRATE = "android.media.mediarecorder.video-bitrate";
1788 
1789         /**
1790          * Key to extract the value for how often video iframes are generated
1791          * from the {@link MediaRecorder#getMetrics} return.
1792          * The value is an integer.
1793          */
1794         public static final String VIDEO_IFRAME_INTERVAL = "android.media.mediarecorder.video-iframe-interval";
1795 
1796         /**
1797          * Key to extract the video encoding level
1798          * from the {@link MediaRecorder#getMetrics} return.
1799          * The value is an integer.
1800          */
1801         public static final String VIDEO_LEVEL = "android.media.mediarecorder.video-encoder-level";
1802 
1803         /**
1804          * Key to extract the video encoding profile
1805          * from the {@link MediaRecorder#getMetrics} return.
1806          * The value is an integer.
1807          */
1808         public static final String VIDEO_PROFILE = "android.media.mediarecorder.video-encoder-profile";
1809 
1810         /**
1811          * Key to extract the recorded video time units
1812          * from the {@link MediaRecorder#getMetrics} return.
1813          * The value is an integer.
1814          * A value of 1000 indicates that the video's timing is in milliseconds.
1815          */
1816         public static final String VIDEO_TIMESCALE = "android.media.mediarecorder.video-timescale";
1817 
1818         /**
1819          * Key to extract the width (in pixels) of the captured video
1820          * from the {@link MediaRecorder#getMetrics} return.
1821          * The value is an integer.
1822          */
1823         public static final String WIDTH = "android.media.mediarecorder.width";
1824 
1825     }
1826 }
1827 
1828