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