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