android_media_MediaRecorder.cpp revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* //device/libs/media_jni/android_media_MediaRecorder.cpp
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "MediaRecorder"
19#include "utils/Log.h"
20
21#include <media/mediarecorder.h>
22#include <stdio.h>
23#include <assert.h>
24#include <limits.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <utils/threads.h>
28
29#include "jni.h"
30#include "JNIHelp.h"
31#include "android_runtime/AndroidRuntime.h"
32
33
34// ----------------------------------------------------------------------------
35
36using namespace android;
37
38// ----------------------------------------------------------------------------
39
40struct fields_t {
41    jfieldID    context;
42    jfieldID    surface;
43    /* actually in android.view.Surface XXX */
44    jfieldID    surface_native;
45};
46static fields_t fields;
47
48// ----------------------------------------------------------------------------
49
50static sp<Surface> get_surface(JNIEnv* env, jobject clazz)
51{
52    Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native);
53    return sp<Surface>(p);
54}
55
56static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message)
57{
58    if (opStatus == (status_t)INVALID_OPERATION) {
59        jniThrowException(env, "java/lang/IllegalStateException", NULL);
60    } else if (opStatus != (status_t)OK) {
61        jniThrowException(env, exception, message);
62    }
63    return;
64}
65
66static void
67android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs)
68{
69    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
70    process_media_recorder_call(env, mr->setVideoSource((video_source)vs), "java/lang/RuntimeException", "setVideoSource failed.");
71}
72
73static void
74android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
75{
76    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
77    process_media_recorder_call(env, mr->setAudioSource((audio_source)as), "java/lang/RuntimeException", "setAudioSource failed.");
78}
79
80static void
81android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of)
82{
83    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
84    process_media_recorder_call(env, mr->setOutputFormat((output_format)of), "java/lang/RuntimeException", "setOutputFormat failed.");
85}
86
87static void
88android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve)
89{
90    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
91    process_media_recorder_call(env, mr->setVideoEncoder((video_encoder)ve), "java/lang/RuntimeException", "setVideoEncoder failed.");
92}
93
94static void
95android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae)
96{
97    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
98    process_media_recorder_call(env, mr->setAudioEncoder((audio_encoder)ae), "java/lang/RuntimeException", "setAudioEncoder failed.");
99}
100
101static void
102android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path)
103{
104    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
105
106    if (path == NULL) {
107        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
108        return;
109    }
110    const char *pathStr = env->GetStringUTFChars(path, NULL);
111    if (pathStr == NULL) {  // Out of memory
112        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
113        return;
114    }
115    status_t opStatus = mr->setOutputFile(pathStr);
116
117    // Make sure that local ref is released before a potential exception
118    env->ReleaseStringUTFChars(path, pathStr);
119    process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed.");
120}
121
122static void
123android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height)
124{
125    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
126    process_media_recorder_call(env, mr->setVideoSize(width, height), "java/lang/RuntimeException", "setVideoSize failed.");
127}
128
129static void
130android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate)
131{
132    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
133    process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed.");
134}
135
136static void
137android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz)
138{
139    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
140
141    jobject surface = env->GetObjectField(thiz, fields.surface);
142    if (surface != NULL) {
143        const sp<Surface>& native_surface = get_surface(env, surface);
144        LOGI("prepare: surface=%p (id=%d)",
145                native_surface.get(), native_surface->ID());
146        process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed.");
147    }
148    process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed.");
149}
150
151static int
152android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz)
153{
154    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
155    int result = 0;
156    process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed.");
157    return result;
158}
159
160static void
161android_media_MediaRecorder_start(JNIEnv *env, jobject thiz)
162{
163    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
164    process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
165}
166
167static void
168android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz)
169{
170    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
171    process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed.");
172}
173
174static void
175android_media_MediaRecorder_reset(JNIEnv *env, jobject thiz)
176{
177    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
178    process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "reset failed.");
179}
180
181static void
182android_media_MediaRecorder_release(JNIEnv *env, jobject thiz)
183{
184    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
185    env->SetIntField(thiz, fields.context, 0);
186    delete mr;
187}
188
189static void
190android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz)
191{
192    MediaRecorder *mr = new MediaRecorder();
193    if (mr == NULL) {
194        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
195        return;
196    }
197
198    process_media_recorder_call(env, mr->init(), "java/lang/RuntimeException", "init failed.");
199    env->SetIntField(thiz, fields.context, (int)mr);
200}
201
202static void
203android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz)
204{
205    MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context);
206
207    //printf("##### android_media_MediaRecorder_native_finalize: ctx=0x%p\n", ctx);
208
209    if (mr == 0)
210        return;
211
212    delete mr;
213}
214
215// ----------------------------------------------------------------------------
216
217static JNINativeMethod gMethods[] = {
218    {"setVideoSource",       "(I)V",                    (void *)android_media_MediaRecorder_setVideoSource},
219    {"setAudioSource",       "(I)V",                    (void *)android_media_MediaRecorder_setAudioSource},
220    {"setOutputFormat",      "(I)V",                    (void *)android_media_MediaRecorder_setOutputFormat},
221    {"setVideoEncoder",      "(I)V",                    (void *)android_media_MediaRecorder_setVideoEncoder},
222    {"setAudioEncoder",      "(I)V",                    (void *)android_media_MediaRecorder_setAudioEncoder},
223    {"setOutputFile",        "(Ljava/lang/String;)V",   (void *)android_media_MediaRecorder_setOutputFile},
224    {"setVideoSize",         "(II)V",                   (void *)android_media_MediaRecorder_setVideoSize},
225    {"setVideoFrameRate",    "(I)V",                    (void *)android_media_MediaRecorder_setVideoFrameRate},
226    {"prepare",              "()V",                     (void *)android_media_MediaRecorder_prepare},
227    {"getMaxAmplitude",      "()I",                     (void *)android_media_MediaRecorder_native_getMaxAmplitude},
228    {"start",                "()V",                     (void *)android_media_MediaRecorder_start},
229    {"stop",                 "()V",                     (void *)android_media_MediaRecorder_stop},
230    {"reset",                "()V",                     (void *)android_media_MediaRecorder_reset},
231    {"release",              "()V",                     (void *)android_media_MediaRecorder_release},
232    {"native_setup",         "()V",                     (void *)android_media_MediaRecorder_native_setup},
233    {"native_finalize",      "()V",                     (void *)android_media_MediaRecorder_native_finalize},
234};
235
236static const char* const kClassPathName = "android/media/MediaRecorder";
237
238int register_android_media_MediaRecorder(JNIEnv *env)
239{
240    jclass clazz;
241
242    clazz = env->FindClass("android/media/MediaRecorder");
243    if (clazz == NULL) {
244        LOGE("Can't find android/media/MediaRecorder");
245        return -1;
246    }
247
248    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
249    if (fields.context == NULL) {
250        LOGE("Can't find MediaRecorder.mNativeContext");
251        return -1;
252    }
253
254    fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
255    if (fields.surface == NULL) {
256        LOGE("Can't find MediaRecorder.mSurface");
257        return -1;
258    }
259
260    jclass surface = env->FindClass("android/view/Surface");
261    if (surface == NULL) {
262        LOGE("Can't find android/view/Surface");
263        return -1;
264    }
265
266    fields.surface_native = env->GetFieldID(surface, "mSurface", "I");
267    if (fields.surface_native == NULL) {
268        LOGE("Can't find Surface fields");
269        return -1;
270    }
271
272    return AndroidRuntime::registerNativeMethods(env,
273                "android/media/MediaRecorder", gMethods, NELEM(gMethods));
274}
275
276
277