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