blob: 915179915b1eab5c845899226f5b902471669abf [file] [log] [blame]
James Dongf3997522011-03-11 12:02:12 -08001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
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
James Dongf3997522011-03-11 12:02:12 -080018//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaScannerJNI"
20#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <utils/threads.h>
James Dongf3997522011-03-11 12:02:12 -080022#include <media/mediascanner.h>
23#include <media/stagefright/StagefrightMediaScanner.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25#include "jni.h"
26#include "JNIHelp.h"
27#include "android_runtime/AndroidRuntime.h"
28
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029using namespace android;
30
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
James Dongf3997522011-03-11 12:02:12 -080032static const char* const kClassMediaScannerClient =
33 "android/media/MediaScannerClient";
34
35static const char* const kClassMediaScanner =
36 "android/media/MediaScanner";
37
38static const char* const kRunTimeException =
39 "java/lang/RuntimeException";
40
41static const char* const kIllegalArgumentException =
42 "java/lang/IllegalArgumentException";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
James Dong133cf8b2011-03-11 15:18:40 -080044struct fields_t {
45 jfieldID context;
46};
47static fields_t fields;
48static Mutex sLock;
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050class MyMediaScannerClient : public MediaScannerClient
51{
52public:
53 MyMediaScannerClient(JNIEnv *env, jobject client)
54 : mEnv(env),
55 mClient(env->NewGlobalRef(client)),
56 mScanFileMethodID(0),
57 mHandleStringTagMethodID(0),
58 mSetMimeTypeMethodID(0)
59 {
James Dongf3997522011-03-11 12:02:12 -080060 LOGV("MyMediaScannerClient constructor");
61 jclass mediaScannerClientInterface =
62 env->FindClass(kClassMediaScannerClient);
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 if (mediaScannerClientInterface == NULL) {
James Dongf3997522011-03-11 12:02:12 -080065 LOGE("Class %s not found", kClassMediaScannerClient);
66 } else {
67 mScanFileMethodID = env->GetMethodID(
68 mediaScannerClientInterface,
69 "scanFile",
Mike Lockwood997354e2011-04-24 11:15:09 -070070 "(Ljava/lang/String;JJZZ)V");
James Dongf3997522011-03-11 12:02:12 -080071
72 mHandleStringTagMethodID = env->GetMethodID(
73 mediaScannerClientInterface,
74 "handleStringTag",
75 "(Ljava/lang/String;Ljava/lang/String;)V");
76
77 mSetMimeTypeMethodID = env->GetMethodID(
78 mediaScannerClientInterface,
79 "setMimeType",
80 "(Ljava/lang/String;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 }
82 }
James Dongf3997522011-03-11 12:02:12 -080083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 virtual ~MyMediaScannerClient()
85 {
James Dongf3997522011-03-11 12:02:12 -080086 LOGV("MyMediaScannerClient destructor");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 mEnv->DeleteGlobalRef(mClient);
88 }
James Dongf3997522011-03-11 12:02:12 -080089
90 // Returns true if it succeeded, false if an exception occured
91 // in the Java code
Mike Lockwood076e05b2010-12-16 12:54:24 -080092 virtual bool scanFile(const char* path, long long lastModified,
Mike Lockwood997354e2011-04-24 11:15:09 -070093 long long fileSize, bool isDirectory, bool noMedia)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 {
James Dongf3997522011-03-11 12:02:12 -080095 LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
96 path, lastModified, fileSize, isDirectory);
97
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 jstring pathStr;
James Dongf3997522011-03-11 12:02:12 -080099 if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
100 return false;
101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Mike Lockwood076e05b2010-12-16 12:54:24 -0800103 mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
Mike Lockwood997354e2011-04-24 11:15:09 -0700104 fileSize, isDirectory, noMedia);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
106 mEnv->DeleteLocalRef(pathStr);
107 return (!mEnv->ExceptionCheck());
108 }
109
James Dongf3997522011-03-11 12:02:12 -0800110 // Returns true if it succeeded, false if an exception occured
111 // in the Java code
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 virtual bool handleStringTag(const char* name, const char* value)
113 {
James Dongf3997522011-03-11 12:02:12 -0800114 LOGV("handleStringTag: name(%s) and value(%s)", name, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 jstring nameStr, valueStr;
James Dongf3997522011-03-11 12:02:12 -0800116 if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
117 return false;
118 }
119 if ((valueStr = mEnv->NewStringUTF(value)) == NULL) {
120 return false;
121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
James Dongf3997522011-03-11 12:02:12 -0800123 mEnv->CallVoidMethod(
124 mClient, mHandleStringTagMethodID, nameStr, valueStr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
126 mEnv->DeleteLocalRef(nameStr);
127 mEnv->DeleteLocalRef(valueStr);
128 return (!mEnv->ExceptionCheck());
129 }
130
James Dongf3997522011-03-11 12:02:12 -0800131 // Returns true if it succeeded, false if an exception occured
132 // in the Java code
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 virtual bool setMimeType(const char* mimeType)
134 {
James Dongf3997522011-03-11 12:02:12 -0800135 LOGV("setMimeType: %s", mimeType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 jstring mimeTypeStr;
James Dongf3997522011-03-11 12:02:12 -0800137 if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) {
138 return false;
139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
141 mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr);
142
143 mEnv->DeleteLocalRef(mimeTypeStr);
144 return (!mEnv->ExceptionCheck());
145 }
146
147private:
148 JNIEnv *mEnv;
149 jobject mClient;
James Dongf3997522011-03-11 12:02:12 -0800150 jmethodID mScanFileMethodID;
151 jmethodID mHandleStringTagMethodID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 jmethodID mSetMimeTypeMethodID;
153};
154
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156static bool ExceptionCheck(void* env)
157{
James Dongf3997522011-03-11 12:02:12 -0800158 LOGV("ExceptionCheck");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 return ((JNIEnv *)env)->ExceptionCheck();
160}
161
James Dong133cf8b2011-03-11 15:18:40 -0800162// Call this method with sLock hold
163static MediaScanner *getNativeScanner_l(JNIEnv* env, jobject thiz)
164{
165 return (MediaScanner *) env->GetIntField(thiz, fields.context);
166}
167
168// Call this method with sLock hold
169static void setNativeScanner_l(JNIEnv* env, jobject thiz, MediaScanner *s)
170{
171 env->SetIntField(thiz, fields.context, (int)s);
172}
173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174static void
James Dongf3997522011-03-11 12:02:12 -0800175android_media_MediaScanner_processDirectory(
176 JNIEnv *env, jobject thiz, jstring path, jobject client)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177{
James Dongf3997522011-03-11 12:02:12 -0800178 LOGV("processDirectory");
James Dong133cf8b2011-03-11 15:18:40 -0800179 Mutex::Autolock l(sLock);
180 MediaScanner *mp = getNativeScanner_l(env, thiz);
181 if (mp == NULL) {
182 jniThrowException(env, kRunTimeException, "No scanner available");
183 return;
184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 if (path == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800187 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 return;
189 }
Mike Lockwoodc37255d2010-09-10 14:47:36 -0400190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 const char *pathStr = env->GetStringUTFChars(path, NULL);
192 if (pathStr == NULL) { // Out of memory
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 return;
194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
196 MyMediaScannerClient myClient(env, client);
Mike Lockwoodc37255d2010-09-10 14:47:36 -0400197 mp->processDirectory(pathStr, myClient, ExceptionCheck, env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 env->ReleaseStringUTFChars(path, pathStr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199}
200
201static void
James Dongf3997522011-03-11 12:02:12 -0800202android_media_MediaScanner_processFile(
203 JNIEnv *env, jobject thiz, jstring path,
204 jstring mimeType, jobject client)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205{
James Dongf3997522011-03-11 12:02:12 -0800206 LOGV("processFile");
James Dong133cf8b2011-03-11 15:18:40 -0800207
208 // Lock already hold by processDirectory
209 MediaScanner *mp = getNativeScanner_l(env, thiz);
210 if (mp == NULL) {
211 jniThrowException(env, kRunTimeException, "No scanner available");
212 return;
213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
215 if (path == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800216 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 return;
218 }
James Dongf3997522011-03-11 12:02:12 -0800219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 const char *pathStr = env->GetStringUTFChars(path, NULL);
221 if (pathStr == NULL) { // Out of memory
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 return;
223 }
James Dongf3997522011-03-11 12:02:12 -0800224
225 const char *mimeTypeStr =
226 (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 if (mimeType && mimeTypeStr == NULL) { // Out of memory
James Dongc371a022011-04-06 12:16:07 -0700228 // ReleaseStringUTFChars can be called with an exception pending.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 env->ReleaseStringUTFChars(path, pathStr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 return;
231 }
232
233 MyMediaScannerClient myClient(env, client);
234 mp->processFile(pathStr, mimeTypeStr, myClient);
235 env->ReleaseStringUTFChars(path, pathStr);
236 if (mimeType) {
237 env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
238 }
239}
240
241static void
James Dongf3997522011-03-11 12:02:12 -0800242android_media_MediaScanner_setLocale(
243 JNIEnv *env, jobject thiz, jstring locale)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244{
James Dongf3997522011-03-11 12:02:12 -0800245 LOGV("setLocale");
James Dong133cf8b2011-03-11 15:18:40 -0800246 Mutex::Autolock l(sLock);
247 MediaScanner *mp = getNativeScanner_l(env, thiz);
248 if (mp == NULL) {
249 jniThrowException(env, kRunTimeException, "No scanner available");
250 return;
251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 if (locale == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800254 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 return;
256 }
257 const char *localeStr = env->GetStringUTFChars(locale, NULL);
258 if (localeStr == NULL) { // Out of memory
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 return;
260 }
261 mp->setLocale(localeStr);
262
263 env->ReleaseStringUTFChars(locale, localeStr);
264}
265
266static jbyteArray
James Dongf3997522011-03-11 12:02:12 -0800267android_media_MediaScanner_extractAlbumArt(
268 JNIEnv *env, jobject thiz, jobject fileDescriptor)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269{
James Dongf3997522011-03-11 12:02:12 -0800270 LOGV("extractAlbumArt");
James Dong133cf8b2011-03-11 15:18:40 -0800271 Mutex::Autolock l(sLock);
272 MediaScanner *mp = getNativeScanner_l(env, thiz);
273 if (mp == NULL) {
274 jniThrowException(env, kRunTimeException, "No scanner available");
275 return NULL;
276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277
278 if (fileDescriptor == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800279 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 return NULL;
281 }
282
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700283 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 char* data = mp->extractAlbumArt(fd);
285 if (!data) {
286 return NULL;
287 }
288 long len = *((long*)data);
James Dongf3997522011-03-11 12:02:12 -0800289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 jbyteArray array = env->NewByteArray(len);
291 if (array != NULL) {
292 jbyte* bytes = env->GetByteArrayElements(array, NULL);
293 memcpy(bytes, data + 4, len);
294 env->ReleaseByteArrayElements(array, bytes, 0);
295 }
James Dongf3997522011-03-11 12:02:12 -0800296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297done:
298 free(data);
299 // if NewByteArray() returned NULL, an out-of-memory
300 // exception will have been raised. I just want to
301 // return null in that case.
302 env->ExceptionClear();
303 return array;
304}
305
Marco Nelissen4935d052009-08-03 11:12:58 -0700306// This function gets a field ID, which in turn causes class initialization.
307// It is called from a static block in MediaScanner, which won't run until the
308// first time an instance of this class is used.
309static void
310android_media_MediaScanner_native_init(JNIEnv *env)
311{
James Dongf3997522011-03-11 12:02:12 -0800312 LOGV("native_init");
313 jclass clazz = env->FindClass(kClassMediaScanner);
Marco Nelissen4935d052009-08-03 11:12:58 -0700314 if (clazz == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700315 return;
316 }
317
318 fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
319 if (fields.context == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700320 return;
321 }
322}
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324static void
325android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
326{
James Dongf3997522011-03-11 12:02:12 -0800327 LOGV("native_setup");
Andreas Huber8d65dd22010-06-23 16:40:57 -0700328 MediaScanner *mp = new StagefrightMediaScanner;
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 if (mp == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800331 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return;
333 }
334
335 env->SetIntField(thiz, fields.context, (int)mp);
336}
337
338static void
339android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
340{
James Dongf3997522011-03-11 12:02:12 -0800341 LOGV("native_finalize");
James Dong133cf8b2011-03-11 15:18:40 -0800342 Mutex::Autolock l(sLock);
343 MediaScanner *mp = getNativeScanner_l(env, thiz);
James Dongf3997522011-03-11 12:02:12 -0800344 if (mp == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 return;
James Dongf3997522011-03-11 12:02:12 -0800346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 delete mp;
James Dong133cf8b2011-03-11 15:18:40 -0800348 setNativeScanner_l(env, thiz, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349}
350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351static JNINativeMethod gMethods[] = {
James Dongf3997522011-03-11 12:02:12 -0800352 {
353 "processDirectory",
354 "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
355 (void *)android_media_MediaScanner_processDirectory
356 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357
James Dongf3997522011-03-11 12:02:12 -0800358 {
359 "processFile",
360 "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
361 (void *)android_media_MediaScanner_processFile
362 },
363
364 {
365 "setLocale",
366 "(Ljava/lang/String;)V",
367 (void *)android_media_MediaScanner_setLocale
368 },
369
370 {
371 "extractAlbumArt",
372 "(Ljava/io/FileDescriptor;)[B",
373 (void *)android_media_MediaScanner_extractAlbumArt
374 },
375
376 {
377 "native_init",
378 "()V",
379 (void *)android_media_MediaScanner_native_init
380 },
381
382 {
383 "native_setup",
384 "()V",
385 (void *)android_media_MediaScanner_native_setup
386 },
387
388 {
389 "native_finalize",
390 "()V",
391 (void *)android_media_MediaScanner_native_finalize
392 },
393};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394
Marco Nelissen4935d052009-08-03 11:12:58 -0700395// This function only registers the native methods, and is called from
396// JNI_OnLoad in android_media_MediaPlayer.cpp
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397int register_android_media_MediaScanner(JNIEnv *env)
398{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return AndroidRuntime::registerNativeMethods(env,
James Dongf3997522011-03-11 12:02:12 -0800400 kClassMediaScanner, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401}