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
JNIMediaRecorderListener(JNIEnv * env,jobject thiz,jobject weak_thiz)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
~JNIMediaRecorderListener()110 JNIMediaRecorderListener::~JNIMediaRecorderListener()
111 {
112 // remove global references
113 JNIEnv *env = AndroidRuntime::getJNIEnv();
114 env->DeleteGlobalRef(mObject);
115 env->DeleteGlobalRef(mClass);
116 }
117
notify(int msg,int ext1,int ext2)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
get_surface(JNIEnv * env,jobject clazz)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
get_persistentSurface(JNIEnv * env,jobject object)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.
process_media_recorder_call(JNIEnv * env,status_t opStatus,const char * exception,const char * message)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
getMediaRecorder(JNIEnv * env,jobject thiz)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
setMediaRecorder(JNIEnv * env,jobject thiz,const sp<MediaRecorder> & recorder)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
android_media_MediaRecorder_setCamera(JNIEnv * env,jobject thiz,jobject camera)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
android_media_MediaRecorder_setVideoSource(JNIEnv * env,jobject thiz,jint vs)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
android_media_MediaRecorder_setAudioSource(JNIEnv * env,jobject thiz,jint as)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
android_media_MediaRecorder_setPrivacySensitive(JNIEnv * env,jobject thiz,jboolean privacySensitive)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
android_media_MediaRecorder_isPrivacySensitive(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_setOutputFormat(JNIEnv * env,jobject thiz,jint of)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
android_media_MediaRecorder_setVideoEncoder(JNIEnv * env,jobject thiz,jint ve)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
android_media_MediaRecorder_setAudioEncoder(JNIEnv * env,jobject thiz,jint ae)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
android_media_MediaRecorder_setParameter(JNIEnv * env,jobject thiz,jstring params)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
android_media_MediaRecorder_setOutputFileFD(JNIEnv * env,jobject thiz,jobject fileDescriptor)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
android_media_MediaRecorder_setNextOutputFileFD(JNIEnv * env,jobject thiz,jobject fileDescriptor)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
android_media_MediaRecorder_setVideoSize(JNIEnv * env,jobject thiz,jint width,jint height)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
android_media_MediaRecorder_setVideoFrameRate(JNIEnv * env,jobject thiz,jint rate)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
android_media_MediaRecorder_setMaxDuration(JNIEnv * env,jobject thiz,jint max_duration_ms)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
android_media_MediaRecorder_setMaxFileSize(JNIEnv * env,jobject thiz,jlong max_filesize_bytes)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
android_media_MediaRecorder_prepare(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_getSurface(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_start(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_stop(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_pause(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_resume(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_native_reset(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_release(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_native_init(JNIEnv * env)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
android_media_MediaRecorder_native_setup(JNIEnv * env,jobject thiz,jobject weak_this,jstring packageName,jobject jAttributionSource)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
android_media_MediaRecorder_native_finalize(JNIEnv * env,jobject thiz)659 android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
660 {
661 ALOGV("finalize");
662 android_media_MediaRecorder_release(env, thiz);
663 }
664
android_media_MediaRecorder_setInputSurface(JNIEnv * env,jobject thiz,jobject object)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
android_media_MediaRecorder_native_getMetrics(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_setInputDevice(JNIEnv * env,jobject thiz,jint device_id)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
android_media_MediaRecorder_getRoutedDeviceId(JNIEnv * env,jobject thiz)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
android_media_MediaRecorder_enableDeviceCallback(JNIEnv * env,jobject thiz,jboolean enabled)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
android_media_MediaRecord_getActiveMicrophones(JNIEnv * env,jobject thiz,jobject jActiveMicrophones)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
android_media_MediaRecord_setPreferredMicrophoneDirection(JNIEnv * env,jobject thiz,jint direction)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
android_media_MediaRecord_setPreferredMicrophoneFieldDimension(JNIEnv * env,jobject thiz,jfloat zoom)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
android_media_MediaRecord_getPortId(JNIEnv * env,jobject thiz)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
register_android_media_MediaRecorder(JNIEnv * env)897 int register_android_media_MediaRecorder(JNIEnv *env)
898 {
899 return AndroidRuntime::registerNativeMethods(env,
900 "android/media/MediaRecorder", gMethods, NELEM(gMethods));
901 }
902