1 /*
2  * Copyright (C) 2008 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 #include <assert.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 
24 //#define LOG_NDEBUG 0
25 #define LOG_TAG "MediaRecorderJNI"
26 #include <utils/Log.h>
27 
28 #include <gui/Surface.h>
29 #include <camera/ICameraService.h>
30 #include <camera/Camera.h>
31 #include <media/mediarecorder.h>
32 #include <media/stagefright/PersistentSurface.h>
33 #include <utils/threads.h>
34 
35 #include <ScopedUtfChars.h>
36 
37 #include "jni.h"
38 #include "JNIHelp.h"
39 #include "android_runtime/AndroidRuntime.h"
40 
41 #include <system/audio.h>
42 #include <android_runtime/android_view_Surface.h>
43 
44 // ----------------------------------------------------------------------------
45 
46 using namespace android;
47 
48 // ----------------------------------------------------------------------------
49 
50 // helper function to extract a native Camera object from a Camera Java object
51 extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context);
52 extern sp<PersistentSurface>
53 android_media_MediaCodec_getPersistentInputSurface(JNIEnv* env, jobject object);
54 
55 struct fields_t {
56     jfieldID    context;
57     jfieldID    surface;
58 
59     jmethodID   post_event;
60 };
61 static fields_t fields;
62 
63 static Mutex sLock;
64 
65 // ----------------------------------------------------------------------------
66 // ref-counted object for callbacks
67 class JNIMediaRecorderListener: public MediaRecorderListener
68 {
69 public:
70     JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
71     ~JNIMediaRecorderListener();
72     void notify(int msg, int ext1, int ext2);
73 private:
74     JNIMediaRecorderListener();
75     jclass      mClass;     // Reference to MediaRecorder class
76     jobject     mObject;    // Weak ref to MediaRecorder Java object to call on
77 };
78 
JNIMediaRecorderListener(JNIEnv * env,jobject thiz,jobject weak_thiz)79 JNIMediaRecorderListener::JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
80 {
81 
82     // Hold onto the MediaRecorder class for use in calling the static method
83     // that posts events to the application thread.
84     jclass clazz = env->GetObjectClass(thiz);
85     if (clazz == NULL) {
86         ALOGE("Can't find android/media/MediaRecorder");
87         jniThrowException(env, "java/lang/Exception", NULL);
88         return;
89     }
90     mClass = (jclass)env->NewGlobalRef(clazz);
91 
92     // We use a weak reference so the MediaRecorder object can be garbage collected.
93     // The reference is only used as a proxy for callbacks.
94     mObject  = env->NewGlobalRef(weak_thiz);
95 }
96 
~JNIMediaRecorderListener()97 JNIMediaRecorderListener::~JNIMediaRecorderListener()
98 {
99     // remove global references
100     JNIEnv *env = AndroidRuntime::getJNIEnv();
101     env->DeleteGlobalRef(mObject);
102     env->DeleteGlobalRef(mClass);
103 }
104 
notify(int msg,int ext1,int ext2)105 void JNIMediaRecorderListener::notify(int msg, int ext1, int ext2)
106 {
107     ALOGV("JNIMediaRecorderListener::notify");
108 
109     JNIEnv *env = AndroidRuntime::getJNIEnv();
110     env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL);
111 }
112 
113 // ----------------------------------------------------------------------------
114 
get_surface(JNIEnv * env,jobject clazz)115 static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
116 {
117     ALOGV("get_surface");
118     return android_view_Surface_getSurface(env, clazz);
119 }
120 
get_persistentSurface(JNIEnv * env,jobject object)121 static sp<PersistentSurface> get_persistentSurface(JNIEnv* env, jobject object)
122 {
123     ALOGV("get_persistentSurface");
124     return android_media_MediaCodec_getPersistentInputSurface(env, object);
125 }
126 
127 // Returns true if it throws an exception.
process_media_recorder_call(JNIEnv * env,status_t opStatus,const char * exception,const char * message)128 static bool process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
129 {
130     ALOGV("process_media_recorder_call");
131     if (opStatus == (status_t)INVALID_OPERATION) {
132         jniThrowException(env, "java/lang/IllegalStateException", NULL);
133         return true;
134     } else if (opStatus != (status_t)OK) {
135         jniThrowException(env, exception, message);
136         return true;
137     }
138     return false;
139 }
140 
getMediaRecorder(JNIEnv * env,jobject thiz)141 static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject thiz)
142 {
143     Mutex::Autolock l(sLock);
144     MediaRecorder* const p = (MediaRecorder*)env->GetLongField(thiz, fields.context);
145     return sp<MediaRecorder>(p);
146 }
147 
setMediaRecorder(JNIEnv * env,jobject thiz,const sp<MediaRecorder> & recorder)148 static sp<MediaRecorder> setMediaRecorder(JNIEnv* env, jobject thiz, const sp<MediaRecorder>& recorder)
149 {
150     Mutex::Autolock l(sLock);
151     sp<MediaRecorder> old = (MediaRecorder*)env->GetLongField(thiz, fields.context);
152     if (recorder.get()) {
153         recorder->incStrong(thiz);
154     }
155     if (old != 0) {
156         old->decStrong(thiz);
157     }
158     env->SetLongField(thiz, fields.context, (jlong)recorder.get());
159     return old;
160 }
161 
162 
android_media_MediaRecorder_setCamera(JNIEnv * env,jobject thiz,jobject camera)163 static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
164 {
165     // we should not pass a null camera to get_native_camera() call.
166     if (camera == NULL) {
167         jniThrowNullPointerException(env, "camera object is a NULL pointer");
168         return;
169     }
170     sp<Camera> c = get_native_camera(env, camera, NULL);
171     if (c == NULL) {
172         // get_native_camera will throw an exception in this case
173         return;
174     }
175     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
176     process_media_recorder_call(env, mr->setCamera(c->remote(), c->getRecordingProxy()),
177             "java/lang/RuntimeException", "setCamera failed.");
178 }
179 
180 static void
android_media_MediaRecorder_setVideoSource(JNIEnv * env,jobject thiz,jint vs)181 android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs)
182 {
183     ALOGV("setVideoSource(%d)", vs);
184     if (vs < VIDEO_SOURCE_DEFAULT || vs >= VIDEO_SOURCE_LIST_END) {
185         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video source");
186         return;
187     }
188     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
189     process_media_recorder_call(env, mr->setVideoSource(vs), "java/lang/RuntimeException", "setVideoSource failed.");
190 }
191 
192 static void
android_media_MediaRecorder_setAudioSource(JNIEnv * env,jobject thiz,jint as)193 android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
194 {
195     ALOGV("setAudioSource(%d)", as);
196     if (as < AUDIO_SOURCE_DEFAULT ||
197         (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
198         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source");
199         return;
200     }
201 
202     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
203     process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
204 }
205 
206 static void
android_media_MediaRecorder_setOutputFormat(JNIEnv * env,jobject thiz,jint of)207 android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
208 {
209     ALOGV("setOutputFormat(%d)", of);
210     if (of < OUTPUT_FORMAT_DEFAULT || of >= OUTPUT_FORMAT_LIST_END) {
211         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid output format");
212         return;
213     }
214     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
215     process_media_recorder_call(env, mr->setOutputFormat(of), "java/lang/RuntimeException", "setOutputFormat failed.");
216 }
217 
218 static void
android_media_MediaRecorder_setVideoEncoder(JNIEnv * env,jobject thiz,jint ve)219 android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
220 {
221     ALOGV("setVideoEncoder(%d)", ve);
222     if (ve < VIDEO_ENCODER_DEFAULT || ve >= VIDEO_ENCODER_LIST_END) {
223         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
224         return;
225     }
226     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
227     process_media_recorder_call(env, mr->setVideoEncoder(ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
228 }
229 
230 static void
android_media_MediaRecorder_setAudioEncoder(JNIEnv * env,jobject thiz,jint ae)231 android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae)
232 {
233     ALOGV("setAudioEncoder(%d)", ae);
234     if (ae < AUDIO_ENCODER_DEFAULT || ae >= AUDIO_ENCODER_LIST_END) {
235         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio encoder");
236         return;
237     }
238     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
239     process_media_recorder_call(env, mr->setAudioEncoder(ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
240 }
241 
242 static void
android_media_MediaRecorder_setParameter(JNIEnv * env,jobject thiz,jstring params)243 android_media_MediaRecorder_setParameter(JNIEnv *env, jobject thiz, jstring params)
244 {
245     ALOGV("setParameter()");
246     if (params == NULL)
247     {
248         ALOGE("Invalid or empty params string.  This parameter will be ignored.");
249         return;
250     }
251 
252     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
253 
254     const char* params8 = env->GetStringUTFChars(params, NULL);
255     if (params8 == NULL)
256     {
257         ALOGE("Failed to covert jstring to String8.  This parameter will be ignored.");
258         return;
259     }
260 
261     process_media_recorder_call(env, mr->setParameters(String8(params8)), "java/lang/RuntimeException", "setParameter failed.");
262     env->ReleaseStringUTFChars(params,params8);
263 }
264 
265 static void
android_media_MediaRecorder_setOutputFileFD(JNIEnv * env,jobject thiz,jobject fileDescriptor,jlong offset,jlong length)266 android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
267 {
268     ALOGV("setOutputFile");
269     if (fileDescriptor == NULL) {
270         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
271         return;
272     }
273     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
274     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
275     status_t opStatus = mr->setOutputFile(fd, offset, length);
276     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
277 }
278 
279 static void
android_media_MediaRecorder_setVideoSize(JNIEnv * env,jobject thiz,jint width,jint height)280 android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height)
281 {
282     ALOGV("setVideoSize(%d, %d)", width, height);
283     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
284 
285     if (width <= 0 || height <= 0) {
286         jniThrowException(env, "java/lang/IllegalArgumentException", "invalid video size");
287         return;
288     }
289     process_media_recorder_call(env, mr->setVideoSize(width, height), "java/lang/RuntimeException", "setVideoSize failed.");
290 }
291 
292 static void
android_media_MediaRecorder_setVideoFrameRate(JNIEnv * env,jobject thiz,jint rate)293 android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
294 {
295     ALOGV("setVideoFrameRate(%d)", rate);
296     if (rate <= 0) {
297         jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
298         return;
299     }
300     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
301     process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed.");
302 }
303 
304 static void
android_media_MediaRecorder_setMaxDuration(JNIEnv * env,jobject thiz,jint max_duration_ms)305 android_media_MediaRecorder_setMaxDuration(JNIEnv *env, jobject thiz, jint max_duration_ms)
306 {
307     ALOGV("setMaxDuration(%d)", max_duration_ms);
308     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
309 
310     char params[64];
311     sprintf(params, "max-duration=%d", max_duration_ms);
312 
313     process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxDuration failed.");
314 }
315 
316 static void
android_media_MediaRecorder_setMaxFileSize(JNIEnv * env,jobject thiz,jlong max_filesize_bytes)317 android_media_MediaRecorder_setMaxFileSize(
318         JNIEnv *env, jobject thiz, jlong max_filesize_bytes)
319 {
320     ALOGV("setMaxFileSize(%lld)", (long long)max_filesize_bytes);
321     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
322 
323     char params[64];
324     sprintf(params, "max-filesize=%" PRId64, max_filesize_bytes);
325 
326     process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxFileSize failed.");
327 }
328 
329 static void
android_media_MediaRecorder_prepare(JNIEnv * env,jobject thiz)330 android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
331 {
332     ALOGV("prepare");
333     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
334 
335     jobject surface = env->GetObjectField(thiz, fields.surface);
336     if (surface != NULL) {
337         const sp<Surface> native_surface = get_surface(env, surface);
338 
339         // The application may misbehave and
340         // the preview surface becomes unavailable
341         if (native_surface.get() == 0) {
342             ALOGE("Application lost the surface");
343             jniThrowException(env, "java/io/IOException", "invalid preview surface");
344             return;
345         }
346 
347         ALOGI("prepare: surface=%p", native_surface.get());
348         if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface->getIGraphicBufferProducer()), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
349             return;
350         }
351     }
352     process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
353 }
354 
355 static jint
android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv * env,jobject thiz)356 android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
357 {
358     ALOGV("getMaxAmplitude");
359     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
360     int result = 0;
361     process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed.");
362     return (jint) result;
363 }
364 
365 static jobject
android_media_MediaRecorder_getSurface(JNIEnv * env,jobject thiz)366 android_media_MediaRecorder_getSurface(JNIEnv *env, jobject thiz)
367 {
368     ALOGV("getSurface");
369     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
370 
371     sp<IGraphicBufferProducer> bufferProducer = mr->querySurfaceMediaSourceFromMediaServer();
372     if (bufferProducer == NULL) {
373         jniThrowException(
374                 env,
375                 "java/lang/IllegalStateException",
376                 "failed to get surface");
377         return NULL;
378     }
379 
380     // Wrap the IGBP in a Java-language Surface.
381     return android_view_Surface_createFromIGraphicBufferProducer(env,
382             bufferProducer);
383 }
384 
385 static void
android_media_MediaRecorder_start(JNIEnv * env,jobject thiz)386 android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
387 {
388     ALOGV("start");
389     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
390     process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
391 }
392 
393 static void
android_media_MediaRecorder_stop(JNIEnv * env,jobject thiz)394 android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
395 {
396     ALOGV("stop");
397     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
398     process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
399 }
400 
401 static void
android_media_MediaRecorder_native_reset(JNIEnv * env,jobject thiz)402 android_media_MediaRecorder_native_reset(JNIEnv *env, jobject thiz)
403 {
404     ALOGV("native_reset");
405     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
406     process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "native_reset failed.");
407 }
408 
409 static void
android_media_MediaRecorder_release(JNIEnv * env,jobject thiz)410 android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
411 {
412     ALOGV("release");
413     sp<MediaRecorder> mr = setMediaRecorder(env, thiz, 0);
414     if (mr != NULL) {
415         mr->setListener(NULL);
416         mr->release();
417     }
418 }
419 
420 // This function gets some field IDs, which in turn causes class initialization.
421 // It is called from a static block in MediaRecorder, which won't run until the
422 // first time an instance of this class is used.
423 static void
android_media_MediaRecorder_native_init(JNIEnv * env)424 android_media_MediaRecorder_native_init(JNIEnv *env)
425 {
426     jclass clazz;
427 
428     clazz = env->FindClass("android/media/MediaRecorder");
429     if (clazz == NULL) {
430         return;
431     }
432 
433     fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
434     if (fields.context == NULL) {
435         return;
436     }
437 
438     fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
439     if (fields.surface == NULL) {
440         return;
441     }
442 
443     jclass surface = env->FindClass("android/view/Surface");
444     if (surface == NULL) {
445         return;
446     }
447 
448     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
449                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
450     if (fields.post_event == NULL) {
451         return;
452     }
453 }
454 
455 
456 static void
android_media_MediaRecorder_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jstring packageName,jstring opPackageName)457 android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
458                                          jstring packageName, jstring opPackageName)
459 {
460     ALOGV("setup");
461 
462     ScopedUtfChars opPackageNameStr(env, opPackageName);
463 
464     sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
465     if (mr == NULL) {
466         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
467         return;
468     }
469     if (mr->initCheck() != NO_ERROR) {
470         jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");
471         return;
472     }
473 
474     // create new listener and give it to MediaRecorder
475     sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
476     mr->setListener(listener);
477 
478     // Convert client name jstring to String16
479     const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
480         env->GetStringChars(packageName, NULL));
481     jsize rawClientNameLen = env->GetStringLength(packageName);
482     String16 clientName(rawClientName, rawClientNameLen);
483     env->ReleaseStringChars(packageName,
484                             reinterpret_cast<const jchar*>(rawClientName));
485 
486     // pass client package name for permissions tracking
487     mr->setClientName(clientName);
488 
489     setMediaRecorder(env, thiz, mr);
490 }
491 
492 static void
android_media_MediaRecorder_native_finalize(JNIEnv * env,jobject thiz)493 android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
494 {
495     ALOGV("finalize");
496     android_media_MediaRecorder_release(env, thiz);
497 }
498 
android_media_MediaRecorder_setInputSurface(JNIEnv * env,jobject thiz,jobject object)499 void android_media_MediaRecorder_setInputSurface(
500         JNIEnv* env, jobject thiz, jobject object) {
501     ALOGV("android_media_MediaRecorder_setInputSurface");
502 
503     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
504 
505     sp<PersistentSurface> persistentSurface = get_persistentSurface(env, object);
506 
507     process_media_recorder_call(env, mr->setInputSurface(persistentSurface),
508             "java/lang/IllegalArgumentException", "native_setInputSurface failed.");
509 }
510 
511 // ----------------------------------------------------------------------------
512 
513 static JNINativeMethod gMethods[] = {
514     {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
515     {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
516     {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
517     {"setOutputFormat",      "(I)V",                            (void *)android_media_MediaRecorder_setOutputFormat},
518     {"setVideoEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setVideoEncoder},
519     {"setAudioEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setAudioEncoder},
520     {"setParameter",         "(Ljava/lang/String;)V",           (void *)android_media_MediaRecorder_setParameter},
521     {"_setOutputFile",       "(Ljava/io/FileDescriptor;JJ)V",   (void *)android_media_MediaRecorder_setOutputFileFD},
522     {"setVideoSize",         "(II)V",                           (void *)android_media_MediaRecorder_setVideoSize},
523     {"setVideoFrameRate",    "(I)V",                            (void *)android_media_MediaRecorder_setVideoFrameRate},
524     {"setMaxDuration",       "(I)V",                            (void *)android_media_MediaRecorder_setMaxDuration},
525     {"setMaxFileSize",       "(J)V",                            (void *)android_media_MediaRecorder_setMaxFileSize},
526     {"_prepare",             "()V",                             (void *)android_media_MediaRecorder_prepare},
527     {"getSurface",           "()Landroid/view/Surface;",        (void *)android_media_MediaRecorder_getSurface},
528     {"getMaxAmplitude",      "()I",                             (void *)android_media_MediaRecorder_native_getMaxAmplitude},
529     {"start",                "()V",                             (void *)android_media_MediaRecorder_start},
530     {"stop",                 "()V",                             (void *)android_media_MediaRecorder_stop},
531     {"native_reset",         "()V",                             (void *)android_media_MediaRecorder_native_reset},
532     {"release",              "()V",                             (void *)android_media_MediaRecorder_release},
533     {"native_init",          "()V",                             (void *)android_media_MediaRecorder_native_init},
534     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V",
535                                                                 (void *)android_media_MediaRecorder_native_setup},
536     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
537     {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface },
538 };
539 
540 // This function only registers the native methods, and is called from
541 // JNI_OnLoad in android_media_MediaPlayer.cpp
register_android_media_MediaRecorder(JNIEnv * env)542 int register_android_media_MediaRecorder(JNIEnv *env)
543 {
544     return AndroidRuntime::registerNativeMethods(env,
545                 "android/media/MediaRecorder", gMethods, NELEM(gMethods));
546 }
547