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