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 #include <vector>
24 
25 //#define LOG_NDEBUG 0
26 #define LOG_TAG "MediaRecorderJNI"
27 #include <utils/Log.h>
28 
29 #include <gui/Surface.h>
30 #include <camera/Camera.h>
31 #include <media/mediarecorder.h>
32 #include <media/MediaMetricsItem.h>
33 #include <media/MicrophoneInfo.h>
34 #include <media/stagefright/PersistentSurface.h>
35 #include <utils/threads.h>
36 
37 #include <nativehelper/ScopedUtfChars.h>
38 
39 #include "jni.h"
40 #include <nativehelper/JNIPlatformHelp.h>
41 #include "android_media_AudioErrors.h"
42 #include "android_media_MediaMetricsJNI.h"
43 #include "android_media_MicrophoneInfo.h"
44 #include "android_runtime/AndroidRuntime.h"
45 
46 #include <system/audio.h>
47 #include <android_runtime/android_view_Surface.h>
48 #include <android/content/AttributionSourceState.h>
49 #include <android_os_Parcel.h>
50 
51 // ----------------------------------------------------------------------------
52 
53 using namespace android;
54 
55 // ----------------------------------------------------------------------------
56 
57 // helper function to extract a native Camera object from a Camera Java object
58 extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context);
59 extern sp<PersistentSurface>
60 android_media_MediaCodec_getPersistentInputSurface(JNIEnv* env, jobject object);
61 
62 struct fields_t {
63     jfieldID    context;
64     jfieldID    surface;
65 
66     jmethodID   post_event;
67 };
68 static fields_t fields;
69 
70 struct ArrayListFields {
71     jmethodID add;
72     jclass classId;
73 };
74 static ArrayListFields gArrayListFields;
75 
76 static Mutex sLock;
77 
78 // ----------------------------------------------------------------------------
79 // ref-counted object for callbacks
80 class JNIMediaRecorderListener: public MediaRecorderListener
81 {
82 public:
83     JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
84     ~JNIMediaRecorderListener();
85     void notify(int msg, int ext1, int ext2);
86 private:
87     JNIMediaRecorderListener();
88     jclass      mClass;     // Reference to MediaRecorder class
89     jobject     mObject;    // Weak ref to MediaRecorder Java object to call on
90 };
91 
92 JNIMediaRecorderListener::JNIMediaRecorderListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
93 {
94 
95     // Hold onto the MediaRecorder class for use in calling the static method
96     // that posts events to the application thread.
97     jclass clazz = env->GetObjectClass(thiz);
98     if (clazz == NULL) {
99         ALOGE("Can't find android/media/MediaRecorder");
100         jniThrowException(env, "java/lang/Exception", NULL);
101         return;
102     }
103     mClass = (jclass)env->NewGlobalRef(clazz);
104 
105     // We use a weak reference so the MediaRecorder object can be garbage collected.
106     // The reference is only used as a proxy for callbacks.
107     mObject  = env->NewGlobalRef(weak_thiz);
108 }
109 
110 JNIMediaRecorderListener::~JNIMediaRecorderListener()
111 {
112     // remove global references
113     JNIEnv *env = AndroidRuntime::getJNIEnv();
114     env->DeleteGlobalRef(mObject);
115     env->DeleteGlobalRef(mClass);
116 }
117 
118 void JNIMediaRecorderListener::notify(int msg, int ext1, int ext2)
119 {
120     ALOGV("JNIMediaRecorderListener::notify");
121 
122     JNIEnv *env = AndroidRuntime::getJNIEnv();
123     env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL);
124 }
125 
126 // ----------------------------------------------------------------------------
127 
128 static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
129 {
130     ALOGV("get_surface");
131     return android_view_Surface_getSurface(env, clazz);
132 }
133 
134 static sp<PersistentSurface> get_persistentSurface(JNIEnv* env, jobject object)
135 {
136     ALOGV("get_persistentSurface");
137     return android_media_MediaCodec_getPersistentInputSurface(env, object);
138 }
139 
140 // Returns true if it throws an exception.
141 static bool process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
142 {
143     ALOGV("process_media_recorder_call");
144     if (opStatus == (status_t)INVALID_OPERATION) {
145         jniThrowException(env, "java/lang/IllegalStateException", NULL);
146         return true;
147     } else if (opStatus != (status_t)OK) {
148         jniThrowException(env, exception, message);
149         return true;
150     }
151     return false;
152 }
153 
154 static sp<MediaRecorder> getMediaRecorder(JNIEnv* env, jobject thiz)
155 {
156     Mutex::Autolock l(sLock);
157     MediaRecorder* const p = (MediaRecorder*)env->GetLongField(thiz, fields.context);
158     return sp<MediaRecorder>(p);
159 }
160 
161 static sp<MediaRecorder> setMediaRecorder(JNIEnv* env, jobject thiz, const sp<MediaRecorder>& recorder)
162 {
163     Mutex::Autolock l(sLock);
164     sp<MediaRecorder> old = (MediaRecorder*)env->GetLongField(thiz, fields.context);
165     if (recorder.get()) {
166         recorder->incStrong(thiz);
167     }
168     if (old != 0) {
169         old->decStrong(thiz);
170     }
171     env->SetLongField(thiz, fields.context, (jlong)recorder.get());
172     return old;
173 }
174 
175 
176 static void android_media_MediaRecorder_setCamera(JNIEnv* env, jobject thiz, jobject camera)
177 {
178     // we should not pass a null camera to get_native_camera() call.
179     if (camera == NULL) {
180         jniThrowNullPointerException(env, "camera object is a NULL pointer");
181         return;
182     }
183     sp<Camera> c = get_native_camera(env, camera, NULL);
184     if (c == NULL) {
185         // get_native_camera will throw an exception in this case
186         return;
187     }
188     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
189     if (mr == NULL) {
190         jniThrowException(env, "java/lang/IllegalStateException", NULL);
191         return;
192     }
193     process_media_recorder_call(env, mr->setCamera(c->remote(), c->getRecordingProxy()),
194             "java/lang/RuntimeException", "setCamera failed.");
195 }
196 
197 static void
198 android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs)
199 {
200     ALOGV("setVideoSource(%d)", vs);
201     if (vs < VIDEO_SOURCE_DEFAULT || vs >= VIDEO_SOURCE_LIST_END) {
202         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video source");
203         return;
204     }
205     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
206     if (mr == NULL) {
207         jniThrowException(env, "java/lang/IllegalStateException", NULL);
208         return;
209     }
210     process_media_recorder_call(env, mr->setVideoSource(vs), "java/lang/RuntimeException", "setVideoSource failed.");
211 }
212 
213 static void
214 android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
215 {
216     ALOGV("setAudioSource(%d)", as);
217     if (as < AUDIO_SOURCE_DEFAULT ||
218         (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) {
219         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source");
220         return;
221     }
222 
223     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
224     if (mr == NULL) {
225         jniThrowException(env, "java/lang/IllegalStateException", NULL);
226         return;
227     }
228     process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
229 }
230 
231 static void
232 android_media_MediaRecorder_setPrivacySensitive(JNIEnv *env, jobject thiz, jboolean privacySensitive)
233 {
234     ALOGV("%s(%s)", __func__, privacySensitive ? "true" : "false");
235 
236     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
237     if (mr == NULL) {
238         jniThrowException(env, "java/lang/IllegalStateException", NULL);
239         return;
240     }
241     process_media_recorder_call(env, mr->setPrivacySensitive(privacySensitive),
242         "java/lang/RuntimeException", "setPrivacySensitive failed.");
243 }
244 
245 static jboolean
246 android_media_MediaRecorder_isPrivacySensitive(JNIEnv *env, jobject thiz)
247 {
248     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
249     if (mr == NULL) {
250         jniThrowException(env, "java/lang/IllegalStateException", NULL);
251         return false;
252     }
253     bool privacySensitive;
254     process_media_recorder_call(env, mr->isPrivacySensitive(&privacySensitive),
255         "java/lang/RuntimeException", "isPrivacySensitive failed.");
256 
257     ALOGV("%s() -> %s", __func__, privacySensitive ? "true" : "false");
258     return privacySensitive;
259 }
260 
261 static void
262 android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
263 {
264     ALOGV("setOutputFormat(%d)", of);
265     if (of < OUTPUT_FORMAT_DEFAULT || of >= OUTPUT_FORMAT_LIST_END) {
266         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid output format");
267         return;
268     }
269     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
270     if (mr == NULL) {
271         jniThrowException(env, "java/lang/IllegalStateException", NULL);
272         return;
273     }
274     process_media_recorder_call(env, mr->setOutputFormat(of), "java/lang/RuntimeException", "setOutputFormat failed.");
275 }
276 
277 static void
278 android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
279 {
280     ALOGV("setVideoEncoder(%d)", ve);
281     if (ve < VIDEO_ENCODER_DEFAULT || ve >= VIDEO_ENCODER_LIST_END) {
282         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid video encoder");
283         return;
284     }
285     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
286     if (mr == NULL) {
287         jniThrowException(env, "java/lang/IllegalStateException", NULL);
288         return;
289     }
290     process_media_recorder_call(env, mr->setVideoEncoder(ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
291 }
292 
293 static void
294 android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae)
295 {
296     ALOGV("setAudioEncoder(%d)", ae);
297     if (ae < AUDIO_ENCODER_DEFAULT || ae >= AUDIO_ENCODER_LIST_END) {
298         jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio encoder");
299         return;
300     }
301     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
302     if (mr == NULL) {
303         jniThrowException(env, "java/lang/IllegalStateException", NULL);
304         return;
305     }
306     process_media_recorder_call(env, mr->setAudioEncoder(ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
307 }
308 
309 static void
310 android_media_MediaRecorder_setParameter(JNIEnv *env, jobject thiz, jstring params)
311 {
312     ALOGV("setParameter()");
313     if (params == NULL)
314     {
315         ALOGE("Invalid or empty params string.  This parameter will be ignored.");
316         return;
317     }
318 
319     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
320     if (mr == NULL) {
321         jniThrowException(env, "java/lang/IllegalStateException", NULL);
322         return;
323     }
324 
325     const char* params8 = env->GetStringUTFChars(params, NULL);
326     if (params8 == NULL)
327     {
328         ALOGE("Failed to covert jstring to String8.  This parameter will be ignored.");
329         return;
330     }
331 
332     process_media_recorder_call(env, mr->setParameters(String8(params8)), "java/lang/RuntimeException", "setParameter failed.");
333     env->ReleaseStringUTFChars(params,params8);
334 }
335 
336 static void
337 android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor)
338 {
339     ALOGV("setOutputFile");
340     if (fileDescriptor == NULL) {
341         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
342         return;
343     }
344     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
345     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
346     if (mr == NULL) {
347         jniThrowException(env, "java/lang/IllegalStateException", NULL);
348         return;
349     }
350     status_t opStatus = mr->setOutputFile(fd);
351     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
352 }
353 
354 static void
355 android_media_MediaRecorder_setNextOutputFileFD(JNIEnv *env, jobject thiz, jobject fileDescriptor)
356 {
357     ALOGV("setNextOutputFile");
358     if (fileDescriptor == NULL) {
359         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
360         return;
361     }
362     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
363     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
364     if (mr == NULL) {
365         jniThrowException(env, "java/lang/IllegalStateException", NULL);
366         return;
367     }
368     status_t opStatus = mr->setNextOutputFile(fd);
369     process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
370 }
371 
372 static void
373 android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height)
374 {
375     ALOGV("setVideoSize(%d, %d)", width, height);
376     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
377     if (mr == NULL) {
378         jniThrowException(env, "java/lang/IllegalStateException", NULL);
379         return;
380     }
381 
382     if (width <= 0 || height <= 0) {
383         jniThrowException(env, "java/lang/IllegalArgumentException", "invalid video size");
384         return;
385     }
386     process_media_recorder_call(env, mr->setVideoSize(width, height), "java/lang/RuntimeException", "setVideoSize failed.");
387 }
388 
389 static void
390 android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
391 {
392     ALOGV("setVideoFrameRate(%d)", rate);
393     if (rate <= 0) {
394         jniThrowException(env, "java/lang/IllegalArgumentException", "invalid frame rate");
395         return;
396     }
397     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
398     if (mr == NULL) {
399         jniThrowException(env, "java/lang/IllegalStateException", NULL);
400         return;
401     }
402     process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed.");
403 }
404 
405 static void
406 android_media_MediaRecorder_setMaxDuration(JNIEnv *env, jobject thiz, jint max_duration_ms)
407 {
408     ALOGV("setMaxDuration(%d)", max_duration_ms);
409     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
410     if (mr == NULL) {
411         jniThrowException(env, "java/lang/IllegalStateException", NULL);
412         return;
413     }
414 
415     char params[64];
416     sprintf(params, "max-duration=%d", max_duration_ms);
417 
418     process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxDuration failed.");
419 }
420 
421 static void
422 android_media_MediaRecorder_setMaxFileSize(
423         JNIEnv *env, jobject thiz, jlong max_filesize_bytes)
424 {
425     ALOGV("setMaxFileSize(%lld)", (long long)max_filesize_bytes);
426     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
427     if (mr == NULL) {
428         jniThrowException(env, "java/lang/IllegalStateException", NULL);
429         return;
430     }
431 
432     char params[64];
433     sprintf(params, "max-filesize=%" PRId64, max_filesize_bytes);
434 
435     process_media_recorder_call(env, mr->setParameters(String8(params)), "java/lang/RuntimeException", "setMaxFileSize failed.");
436 }
437 
438 static void
439 android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
440 {
441     ALOGV("prepare");
442     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
443     if (mr == NULL) {
444         jniThrowException(env, "java/lang/IllegalStateException", NULL);
445         return;
446     }
447 
448     jobject surface = env->GetObjectField(thiz, fields.surface);
449     if (surface != NULL) {
450         const sp<Surface> native_surface = get_surface(env, surface);
451 
452         // The application may misbehave and
453         // the preview surface becomes unavailable
454         if (native_surface.get() == 0) {
455             ALOGE("Application lost the surface");
456             jniThrowException(env, "java/io/IOException", "invalid preview surface");
457             return;
458         }
459 
460         ALOGI("prepare: surface=%p", native_surface.get());
461         if (process_media_recorder_call(env, mr->setPreviewSurface(native_surface->getIGraphicBufferProducer()), "java/lang/RuntimeException", "setPreviewSurface failed.")) {
462             return;
463         }
464     }
465     process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
466 }
467 
468 static jint
469 android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
470 {
471     ALOGV("getMaxAmplitude");
472     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
473     if (mr == NULL) {
474         jniThrowException(env, "java/lang/IllegalStateException", NULL);
475         return 0;
476     }
477     int result = 0;
478     process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed.");
479     return (jint) result;
480 }
481 
482 static jobject
483 android_media_MediaRecorder_getSurface(JNIEnv *env, jobject thiz)
484 {
485     ALOGV("getSurface");
486     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
487     if (mr == NULL) {
488         jniThrowException(env, "java/lang/IllegalStateException", NULL);
489         return NULL;
490     }
491 
492     sp<IGraphicBufferProducer> bufferProducer = mr->querySurfaceMediaSourceFromMediaServer();
493     if (bufferProducer == NULL) {
494         jniThrowException(
495                 env,
496                 "java/lang/IllegalStateException",
497                 "failed to get surface");
498         return NULL;
499     }
500 
501     // Wrap the IGBP in a Java-language Surface.
502     return android_view_Surface_createFromIGraphicBufferProducer(env,
503             bufferProducer);
504 }
505 
506 static void
507 android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
508 {
509     ALOGV("start");
510     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
511     if (mr == NULL) {
512         jniThrowException(env, "java/lang/IllegalStateException", NULL);
513         return;
514     }
515     process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
516 }
517 
518 static void
519 android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
520 {
521     ALOGV("stop");
522     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
523     if (mr == NULL) {
524         jniThrowException(env, "java/lang/IllegalStateException", NULL);
525         return;
526     }
527     process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
528 }
529 
530 static void
531 android_media_MediaRecorder_pause(JNIEnv *env, jobject thiz)
532 {
533     ALOGV("pause");
534     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
535     if (mr == NULL) {
536         jniThrowException(env, "java/lang/IllegalStateException", NULL);
537         return;
538     }
539     process_media_recorder_call(env, mr->pause(), "java/lang/RuntimeException", "pause failed.");
540 }
541 
542 static void
543 android_media_MediaRecorder_resume(JNIEnv *env, jobject thiz)
544 {
545     ALOGV("resume");
546     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
547     if (mr == NULL) {
548         jniThrowException(env, "java/lang/IllegalStateException", NULL);
549         return;
550     }
551     process_media_recorder_call(env, mr->resume(), "java/lang/RuntimeException", "resume failed.");
552 }
553 
554 static void
555 android_media_MediaRecorder_native_reset(JNIEnv *env, jobject thiz)
556 {
557     ALOGV("native_reset");
558     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
559     if (mr == NULL) {
560         jniThrowException(env, "java/lang/IllegalStateException", NULL);
561         return;
562     }
563     process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "native_reset failed.");
564 }
565 
566 static void
567 android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
568 {
569     ALOGV("release");
570     sp<MediaRecorder> mr = setMediaRecorder(env, thiz, 0);
571     if (mr != NULL) {
572         mr->setListener(NULL);
573         mr->release();
574     }
575 }
576 
577 // This function gets some field IDs, which in turn causes class initialization.
578 // It is called from a static block in MediaRecorder, which won't run until the
579 // first time an instance of this class is used.
580 static void
581 android_media_MediaRecorder_native_init(JNIEnv *env)
582 {
583     jclass clazz;
584 
585     clazz = env->FindClass("android/media/MediaRecorder");
586     if (clazz == NULL) {
587         return;
588     }
589 
590     fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
591     if (fields.context == NULL) {
592         return;
593     }
594 
595     fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
596     if (fields.surface == NULL) {
597         return;
598     }
599 
600     jclass surface = env->FindClass("android/view/Surface");
601     if (surface == NULL) {
602         return;
603     }
604 
605     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
606                                                "(Ljava/lang/Object;IIILjava/lang/Object;)V");
607     if (fields.post_event == NULL) {
608         return;
609     }
610 
611     clazz = env->FindClass("java/util/ArrayList");
612     if (clazz == NULL) {
613         return;
614     }
615     gArrayListFields.add = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z");
616     gArrayListFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
617 }
618 
619 
620 static void
621 android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
622                                          jstring packageName, jobject jAttributionSource)
623 {
624     ALOGV("setup");
625 
626     Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
627     android::content::AttributionSourceState attributionSource;
628     attributionSource.readFromParcel(parcel);
629     sp<MediaRecorder> mr = new MediaRecorder(attributionSource);
630 
631     if (mr == NULL) {
632         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
633         return;
634     }
635     if (mr->initCheck() != NO_ERROR) {
636         jniThrowException(env, "java/lang/RuntimeException", "Unable to initialize media recorder");
637         return;
638     }
639 
640     // create new listener and give it to MediaRecorder
641     sp<JNIMediaRecorderListener> listener = new JNIMediaRecorderListener(env, thiz, weak_this);
642     mr->setListener(listener);
643 
644     // Convert client name jstring to String16
645     const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
646         env->GetStringChars(packageName, NULL));
647     jsize rawClientNameLen = env->GetStringLength(packageName);
648     String16 clientName(rawClientName, rawClientNameLen);
649     env->ReleaseStringChars(packageName,
650                             reinterpret_cast<const jchar*>(rawClientName));
651 
652     // pass client package name for permissions tracking
653     mr->setClientName(clientName);
654 
655     setMediaRecorder(env, thiz, mr);
656 }
657 
658 static void
659 android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
660 {
661     ALOGV("finalize");
662     android_media_MediaRecorder_release(env, thiz);
663 }
664 
665 void android_media_MediaRecorder_setInputSurface(
666         JNIEnv* env, jobject thiz, jobject object) {
667     ALOGV("android_media_MediaRecorder_setInputSurface");
668 
669     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
670     if (mr == NULL) {
671         jniThrowException(env, "java/lang/IllegalStateException", NULL);
672         return;
673     }
674 
675     sp<PersistentSurface> persistentSurface = get_persistentSurface(env, object);
676 
677     process_media_recorder_call(env, mr->setInputSurface(persistentSurface),
678             "java/lang/IllegalArgumentException", "native_setInputSurface failed.");
679 }
680 
681 static jobject
682 android_media_MediaRecorder_native_getMetrics(JNIEnv *env, jobject thiz)
683 {
684     ALOGV("android_media_MediaRecorder_native_getMetrics");
685 
686     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
687     if (mr == NULL) {
688         jniThrowException(env, "java/lang/IllegalStateException", NULL);
689         return NULL;
690     }
691 
692     // get what we have for the metrics from the codec
693     Parcel reply;
694     status_t err = mr->getMetrics(&reply);
695     if (err != OK) {
696         ALOGE("getMetrics failed");
697         return (jobject) NULL;
698     }
699 
700     // build and return the Bundle
701     std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create());
702     item->readFromParcel(reply);
703     jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item.get(), NULL);
704 
705     return mybundle;
706 }
707 
708 static jboolean
709 android_media_MediaRecorder_setInputDevice(JNIEnv *env, jobject thiz, jint device_id)
710 {
711     ALOGV("android_media_MediaRecorder_setInputDevice");
712 
713     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
714     if (mr == NULL) {
715         jniThrowException(env, "java/lang/IllegalStateException", NULL);
716         return false;
717     }
718 
719     if (process_media_recorder_call(env, mr->setInputDevice(device_id),
720             "java/lang/RuntimeException", "setInputDevice failed.")) {
721         return false;
722     }
723     return true;
724 }
725 
726 static jint
727 android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz)
728 {
729     ALOGV("android_media_MediaRecorder_getRoutedDeviceId");
730 
731     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
732     if (mr == NULL) {
733         jniThrowException(env, "java/lang/IllegalStateException", NULL);
734         return AUDIO_PORT_HANDLE_NONE;
735     }
736 
737     audio_port_handle_t deviceId;
738     process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId),
739             "java/lang/RuntimeException", "getRoutedDeviceId failed.");
740     return (jint) deviceId;
741 }
742 
743 static void
744 android_media_MediaRecorder_enableDeviceCallback(JNIEnv *env, jobject thiz, jboolean enabled)
745 {
746     ALOGV("android_media_MediaRecorder_enableDeviceCallback %d", enabled);
747 
748     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
749     if (mr == NULL) {
750         jniThrowException(env, "java/lang/IllegalStateException", NULL);
751         return;
752     }
753 
754     process_media_recorder_call(env, mr->enableAudioDeviceCallback(enabled),
755             "java/lang/RuntimeException", "enableDeviceCallback failed.");
756 }
757 
758 static jint
759 android_media_MediaRecord_getActiveMicrophones(JNIEnv *env,
760         jobject thiz, jobject jActiveMicrophones) {
761     if (jActiveMicrophones == NULL) {
762         ALOGE("jActiveMicrophones is null");
763         return (jint)AUDIO_JAVA_BAD_VALUE;
764     }
765     if (!env->IsInstanceOf(jActiveMicrophones, gArrayListFields.classId)) {
766         ALOGE("getActiveMicrophones not an arraylist");
767         return (jint)AUDIO_JAVA_BAD_VALUE;
768     }
769 
770     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
771     if (mr == NULL) {
772         jniThrowException(env, "java/lang/IllegalStateException", NULL);
773         return (jint)AUDIO_JAVA_NO_INIT;
774     }
775 
776     jint jStatus = AUDIO_JAVA_SUCCESS;
777     std::vector<media::MicrophoneInfo> activeMicrophones;
778     status_t status = mr->getActiveMicrophones(&activeMicrophones);
779     if (status != NO_ERROR) {
780         ALOGE_IF(status != NO_ERROR, "MediaRecorder::getActiveMicrophones error %d", status);
781         jStatus = nativeToJavaStatus(status);
782         return jStatus;
783     }
784 
785     for (size_t i = 0; i < activeMicrophones.size(); i++) {
786         jobject jMicrophoneInfo;
787         jStatus = convertMicrophoneInfoFromNative(env, &jMicrophoneInfo, &activeMicrophones[i]);
788         if (jStatus != AUDIO_JAVA_SUCCESS) {
789             return jStatus;
790         }
791         env->CallBooleanMethod(jActiveMicrophones, gArrayListFields.add, jMicrophoneInfo);
792         env->DeleteLocalRef(jMicrophoneInfo);
793     }
794     return jStatus;
795 }
796 
797 static jint android_media_MediaRecord_setPreferredMicrophoneDirection(
798         JNIEnv *env, jobject thiz, jint direction) {
799     ALOGV("setPreferredMicrophoneDirection(%d)", direction);
800     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
801     if (mr == NULL) {
802         jniThrowException(env, "java/lang/IllegalStateException", NULL);
803         return (jint)AUDIO_JAVA_NO_INIT;
804     }
805 
806     jint jStatus = AUDIO_JAVA_SUCCESS;
807     status_t status =
808         mr->setPreferredMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
809     if (status != NO_ERROR) {
810         jStatus = nativeToJavaStatus(status);
811     }
812 
813     return jStatus;
814 }
815 
816 static jint  android_media_MediaRecord_setPreferredMicrophoneFieldDimension(
817         JNIEnv *env, jobject thiz, jfloat zoom) {
818     ALOGV("setPreferredMicrophoneFieldDimension(%f)", zoom);
819     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
820     if (mr == NULL) {
821         jniThrowException(env, "java/lang/IllegalStateException", NULL);
822         return (jint)AUDIO_JAVA_NO_INIT;
823     }
824 
825     jint jStatus = AUDIO_JAVA_SUCCESS;
826     status_t status = mr->setPreferredMicrophoneFieldDimension(zoom);
827     if (status != NO_ERROR) {
828         jStatus = nativeToJavaStatus(status);
829     }
830 
831     return jStatus;
832 
833 }
834 
835 static jint android_media_MediaRecord_getPortId(JNIEnv *env,  jobject thiz) {
836     sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
837     if (mr == NULL) {
838         jniThrowException(env, "java/lang/IllegalStateException", NULL);
839         return (jint)AUDIO_PORT_HANDLE_NONE;
840     }
841 
842     audio_port_handle_t portId;
843     process_media_recorder_call(env, mr->getPortId(&portId),
844                                 "java/lang/RuntimeException", "getPortId failed.");
845     return (jint)portId;
846 }
847 
848 // ----------------------------------------------------------------------------
849 
850 static const JNINativeMethod gMethods[] = {
851     {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
852     {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
853     {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
854     {"setPrivacySensitive",  "(Z)V",                            (void *)android_media_MediaRecorder_setPrivacySensitive},
855     {"isPrivacySensitive",  "()Z",                             (void *)android_media_MediaRecorder_isPrivacySensitive},
856     {"setOutputFormat",      "(I)V",                            (void *)android_media_MediaRecorder_setOutputFormat},
857     {"setVideoEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setVideoEncoder},
858     {"setAudioEncoder",      "(I)V",                            (void *)android_media_MediaRecorder_setAudioEncoder},
859     {"setParameter",         "(Ljava/lang/String;)V",           (void *)android_media_MediaRecorder_setParameter},
860     {"_setOutputFile",       "(Ljava/io/FileDescriptor;)V",     (void *)android_media_MediaRecorder_setOutputFileFD},
861     {"_setNextOutputFile",   "(Ljava/io/FileDescriptor;)V",     (void *)android_media_MediaRecorder_setNextOutputFileFD},
862     {"setVideoSize",         "(II)V",                           (void *)android_media_MediaRecorder_setVideoSize},
863     {"setVideoFrameRate",    "(I)V",                            (void *)android_media_MediaRecorder_setVideoFrameRate},
864     {"setMaxDuration",       "(I)V",                            (void *)android_media_MediaRecorder_setMaxDuration},
865     {"setMaxFileSize",       "(J)V",                            (void *)android_media_MediaRecorder_setMaxFileSize},
866     {"_prepare",             "()V",                             (void *)android_media_MediaRecorder_prepare},
867     {"getSurface",           "()Landroid/view/Surface;",        (void *)android_media_MediaRecorder_getSurface},
868     {"getMaxAmplitude",      "()I",                             (void *)android_media_MediaRecorder_native_getMaxAmplitude},
869     {"start",                "()V",                             (void *)android_media_MediaRecorder_start},
870     {"stop",                 "()V",                             (void *)android_media_MediaRecorder_stop},
871     {"pause",                "()V",                             (void *)android_media_MediaRecorder_pause},
872     {"resume",               "()V",                             (void *)android_media_MediaRecorder_resume},
873     {"native_reset",         "()V",                             (void *)android_media_MediaRecorder_native_reset},
874     {"release",              "()V",                             (void *)android_media_MediaRecorder_release},
875     {"native_init",          "()V",                             (void *)android_media_MediaRecorder_native_init},
876     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Landroid/os/Parcel;)V",
877                                                                 (void *)android_media_MediaRecorder_native_setup},
878     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
879     {"native_setInputSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaRecorder_setInputSurface },
880 
881     {"native_getMetrics",    "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics},
882 
883     {"native_setInputDevice", "(I)Z",                           (void *)android_media_MediaRecorder_setInputDevice},
884     {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaRecorder_getRoutedDeviceId},
885     {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaRecorder_enableDeviceCallback},
886 
887     {"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones},
888     {"native_getPortId", "()I", (void *)android_media_MediaRecord_getPortId},
889     {"native_setPreferredMicrophoneDirection", "(I)I",
890             (void *)android_media_MediaRecord_setPreferredMicrophoneDirection},
891     {"native_setPreferredMicrophoneFieldDimension", "(F)I",
892             (void *)android_media_MediaRecord_setPreferredMicrophoneFieldDimension},
893 };
894 
895 // This function only registers the native methods, and is called from
896 // JNI_OnLoad in android_media_MediaPlayer.cpp
897 int register_android_media_MediaRecorder(JNIEnv *env)
898 {
899     return AndroidRuntime::registerNativeMethods(env,
900                 "android/media/MediaRecorder", gMethods, NELEM(gMethods));
901 }
902