summaryrefslogtreecommitdiff
path: root/tvapi/android/jni/com_droidlogic_app_tv_TvControlManager.cpp (plain)
blob: 0cc30df607a9a5d32d1640d2d2ec38fec7e10f9b
1#define LOG_TAG "Tv-JNI"
2#include <utils/Log.h>
3
4#include "../include/tvcmd.h"
5#include "jni.h"
6#include "JNIHelp.h"
7#include "GraphicsJNI.h"
8#include "android_runtime/AndroidRuntime.h"
9#include <utils/Vector.h>
10#include <include/TvClient.h>
11#include <binder/IMemory.h>
12#include <binder/Parcel.h>
13#include <binder/MemoryHeapBase.h>
14#include <binder/MemoryBase.h>
15#include <core/SkBitmap.h>
16#include "android_util_Binder.h"
17#include "android_os_Parcel.h"
18using namespace android;
19
20struct fields_t {
21 jfieldID context;
22 jmethodID post_event;
23};
24
25static fields_t fields;
26static Mutex sLock;
27class JNITvContext: public TvListener {
28public:
29 JNITvContext(JNIEnv *env, jobject weak_this, jclass clazz, const sp<TvClient> &tv);
30 ~JNITvContext()
31 {
32 release();
33 }
34 virtual void notify(int32_t msgType, const Parcel &p);
35 void addCallbackBuffer(JNIEnv *env, jbyteArray cbb);
36 sp<TvClient> getTv()
37 {
38 Mutex::Autolock _l(mLock);
39 return mTv;
40 }
41 void release();
42 Parcel *mExtParcel;
43 SkBitmap *pSubBmp;//for UI subtitle Bitmap
44 sp<MemoryBase> mSubMemBase;//for subtitle shar memory to tvapi
45private:
46 jobject mTvJObjectWeak; // weak reference to java object
47 jclass mTvJClass; // strong reference to java class
48 sp<TvClient> mTv; // strong reference to native object
49 Mutex mLock;
50
51 Vector<jbyteArray> mCallbackBuffers; // Global reference application managed byte[]
52 bool mManualBufferMode; // Whether to use application managed buffers.
53 bool mManualTvCallbackSet; // Whether the callback has been set, used to reduce unnecessary calls to set the callback.
54};
55
56sp<TvClient> get_native_tv(JNIEnv *env, jobject thiz, JNITvContext **pContext)
57{
58 sp<TvClient> tv;
59 Mutex::Autolock _l(sLock);
60 JNITvContext *context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
61 if (context != NULL) {
62 tv = context->getTv();
63 }
64 if (tv == 0) {
65 jniThrowException(env, "java/lang/RuntimeException", "Method called after release()");
66 }
67
68 if (pContext != NULL) *pContext = context;
69 return tv;
70}
71
72JNITvContext::JNITvContext(JNIEnv *env, jobject weak_this, jclass clazz, const sp<TvClient> &tv)
73{
74 mTvJObjectWeak = env->NewGlobalRef(weak_this);
75 mTvJClass = (jclass)env->NewGlobalRef(clazz);
76 mTv = tv;
77 ALOGD("tvjni----------------------JNITvContext::JNITvContext(");
78 mManualBufferMode = false;
79 mManualTvCallbackSet = false;
80 pSubBmp = NULL;
81 mSubMemBase = NULL;
82 //mExtParcel = parcelForJavaObject(env, ext_parcel);
83}
84
85void JNITvContext::release()
86{
87 ALOGD("release");
88 Mutex::Autolock _l(mLock);
89 JNIEnv *env = AndroidRuntime::getJNIEnv();
90
91 if (mTvJObjectWeak != NULL) {
92 env->DeleteGlobalRef(mTvJObjectWeak);
93 mTvJObjectWeak = NULL;
94 }
95 if (mTvJClass != NULL) {
96 env->DeleteGlobalRef(mTvJClass);
97 mTvJClass = NULL;
98 }
99 if (pSubBmp != NULL) {
100 pSubBmp = NULL;
101 }
102 mTv.clear();
103}
104
105// connect to tv service
106static void com_droidlogic_app_tv_TvControlManager_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
107{
108 sp<TvClient> tv = TvClient::connect();
109
110 ALOGD("com_droidlogic_app_tv_TvControlManager_native_setup.");
111
112 if (tv == NULL) {
113 jniThrowException(env, "java/lang/RuntimeException", "Fail to connect to tv service");
114 return;
115 }
116
117 // make sure tv amlogic is alive
118 if (tv->getStatus() != NO_ERROR) {
119 jniThrowException(env, "java/lang/RuntimeException", "Tv initialization failed!");
120 return;
121 }
122
123 jclass clazz = env->GetObjectClass(thiz);
124 if (clazz == NULL) {
125 jniThrowException(env, "java/lang/RuntimeException", "Can't find com/droidlogic/app/tv/TvControlManager!");
126 return;
127 }
128
129 sp<JNITvContext> context = new JNITvContext(env, weak_this, clazz, tv);
130 context->incStrong(thiz);
131 tv->setListener(context);
132
133 env->SetIntField(thiz, fields.context, (int)context.get());
134}
135
136
137static void com_droidlogic_app_tv_TvControlManager_release(JNIEnv *env, jobject thiz)
138{
139 // TODO: Change to LOGE
140 JNITvContext *context = NULL;
141 sp<TvClient> tv;
142 {
143 Mutex::Autolock _l(sLock);
144 context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
145
146 // Make sure we do not attempt to callback on a deleted Java object.
147 env->SetIntField(thiz, fields.context, 0);
148 }
149
150 ALOGD("release tv");
151
152 // clean up if release has not been called before
153 if (context != NULL) {
154 tv = context->getTv();
155 context->release();
156 ALOGD("native_release: context=%p tv=%p", context, tv.get());
157
158 // clear callbacks
159 if (tv != NULL) {
160 //tv->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
161 tv->disconnect();
162 }
163
164 // remove context to prevent further Java access
165 context->decStrong(thiz);
166 }
167}
168
169void JNITvContext::notify(int32_t msgType, const Parcel &p)
170{
171 // VM pointer will be NULL if object is released
172 Mutex::Autolock _l(mLock);
173 if (mTvJObjectWeak == NULL) {
174 ALOGW("callback on dead tv object");
175 return;
176 }
177 if (msgType == SUBTITLE_UPDATE_CALLBACK) {
178 if (pSubBmp) {
179 SkAutoLockPixels alp(*pSubBmp);
180 char *pDst = (char *) pSubBmp->getPixels();
181 char *pBuf = (char *) mSubMemBase->pointer();
182 for (int i = 0; i < pSubBmp->width() * pSubBmp->height() * 4; i++) {
183 pDst[i] = pBuf[i];
184 }
185 pSubBmp->notifyPixelsChanged();
186 }
187 }
188
189 JNIEnv *env = AndroidRuntime::getJNIEnv();
190
191 jobject jParcel = createJavaParcelObject(env);
192 if (jParcel != NULL) {
193 Parcel *nativeParcel = parcelForJavaObject(env, jParcel);
194 nativeParcel->write(p.data(), p.dataSize());
195 env->CallStaticVoidMethod(mTvJClass, fields.post_event, mTvJObjectWeak, msgType, jParcel);
196 env->DeleteLocalRef(jParcel);
197 }
198}
199
200
201void JNITvContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb)
202{
203 if (cbb != NULL) {
204 Mutex::Autolock _l(mLock);
205 jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb);
206 mCallbackBuffers.push(cbb);
207 ALOGD("Adding callback buffer to queue, %d total", mCallbackBuffers.size());
208 } else {
209 ALOGE("Null byte array!");
210 }
211}
212
213static jint com_droidlogic_app_tv_TvControlManager_processCmd(JNIEnv *env, jobject thiz, jobject pObj, jobject rObj)
214{
215 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
216 if (tv == 0) return -1;
217
218 Parcel *p = parcelForJavaObject(env, pObj);
219 //jclass clazz;
220 //clazz = env->FindClass("android/os/Parcel");
221 //LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Parcel");
222
223
224 //jmethodID mConstructor = env->GetMethodID(clazz, "<init>", "(I)V");
225 //jobject replayobj = env->NewObject(clazz, mConstructor, 0);
226 Parcel *r = parcelForJavaObject(env, rObj);
227
228
229 return tv->processCmd(*p, r);
230 //if ( != NO_ERROR) {
231 // jniThrowException(env, "java/lang/RuntimeException", "StartTv failed");
232 // return -1;
233 // }
234 //return 0;
235}
236
237static void com_droidlogic_app_tv_TvControlManager_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes)
238{
239 JNITvContext *context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
240
241 ALOGD("addCallbackBuffer");
242 if (context != NULL) {
243 context->addCallbackBuffer(env, bytes);
244 }
245}
246
247static void com_droidlogic_app_tv_TvControlManager_reconnect(JNIEnv *env, jobject thiz)
248{
249 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
250 if (tv == 0) return;
251
252 if (tv->reconnect() != NO_ERROR) {
253 jniThrowException(env, "java/io/IOException", "reconnect failed");
254 return;
255 }
256}
257
258static void com_droidlogic_app_tv_TvControlManager_lock(JNIEnv *env, jobject thiz)
259{
260 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
261 if (tv == 0) return;
262
263 ALOGD("lock");
264
265 if (tv->lock() != NO_ERROR) {
266 jniThrowException(env, "java/lang/RuntimeException", "lock failed");
267 }
268}
269
270static void com_droidlogic_app_tv_TvControlManager_unlock(JNIEnv *env, jobject thiz)
271{
272 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
273 if (tv == 0) return;
274
275 ALOGD("unlock");
276
277 if (tv->unlock() != NO_ERROR) {
278 jniThrowException(env, "java/lang/RuntimeException", "unlock failed");
279 }
280}
281
282static void com_droidlogic_app_tv_TvControlManager_create_subtitle_bitmap(JNIEnv *env, jobject thiz, jobject bmpobj)
283{
284 ALOGD("create subtitle bmp");
285 JNITvContext *context = reinterpret_cast<JNITvContext *>(env->GetIntField(thiz, fields.context));
286 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
287 if (tv == 0) return;
288
289 //get skbitmap
290 jclass bmp_clazz;
291 jfieldID skbmp_fid;
292 jint hbmp;
293 bmp_clazz = env->FindClass("android/graphics/Bitmap");
294 skbmp_fid = env->GetFieldID(bmp_clazz, "mNativeBitmap", "I");
295 hbmp = env->GetIntField(bmpobj, skbmp_fid);
296 context->pSubBmp = reinterpret_cast<SkBitmap *>(hbmp);
297 env->DeleteLocalRef(bmp_clazz);
298
299 //alloc share mem
300 sp<MemoryHeapBase> MemHeap = new MemoryHeapBase(context->pSubBmp->width()*context->pSubBmp->height() * 4, 0, "subtitle bmp");
301 ALOGD("heap id = %d", MemHeap->getHeapID());
302 if (MemHeap->getHeapID() < 0) {
303 return;
304 }
305 context->pSubBmp->lockPixels();
306 context->mSubMemBase = new MemoryBase(MemHeap, 0, context->pSubBmp->width()*context->pSubBmp->height() * 4);
307
308
309 //send share mem to server
310 tv->createSubtitle(context->mSubMemBase);
311 return;
312}
313
314static void com_droidlogic_app_tv_TvControlManager_create_video_frame_bitmap(JNIEnv *env, jobject thiz, jobject bmpobj, jint inputSourceMode, jint iCapVideoLayer )
315{
316 ALOGD("create video frame bmp");
317 sp<TvClient> tv = get_native_tv(env, thiz, NULL);
318 if (tv == 0) return;
319
320 //get skbitmap
321 jclass bmp_clazz;
322 jfieldID skbmp_fid;
323 jint hbmp;
324 bmp_clazz = env->FindClass("android/graphics/Bitmap");
325 skbmp_fid = env->GetFieldID(bmp_clazz, "mNativeBitmap", "I");
326 hbmp = env->GetIntField(bmpobj, skbmp_fid);
327 SkBitmap *pSkBmp = reinterpret_cast<SkBitmap *>(hbmp);
328 ALOGD("pSkBmp = %d", hbmp);
329 ALOGD("bmp width = %d height = %d", pSkBmp->width(), pSkBmp->height());
330 env->DeleteLocalRef(bmp_clazz);
331
332 //alloc share mem
333 sp<MemoryHeapBase> MemHeap = new MemoryHeapBase(1920 * 1080 * 4, 0, "video frame bmp");
334 ALOGD("heap id = %d", MemHeap->getHeapID());
335 if (MemHeap->getHeapID() < 0) {
336 return;
337 }
338 sp<MemoryBase> MemBase = new MemoryBase(MemHeap, 0, 1920 * 1080 * 4);
339 pSkBmp->setPixels(MemBase->pointer());
340
341
342 //send share mem to server
343 tv->createVideoFrame(MemBase, inputSourceMode, iCapVideoLayer);
344 return;
345}
346
347//-------------------------------------------------
348
349static JNINativeMethod camMethods[] = {
350 {
351 "native_setup",
352 "(Ljava/lang/Object;)V",
353 (void *)com_droidlogic_app_tv_TvControlManager_native_setup
354 },
355 {
356 "native_release",
357 "()V",
358 (void *)com_droidlogic_app_tv_TvControlManager_release
359 },
360 {
361 "processCmd",
362 "(Landroid/os/Parcel;Landroid/os/Parcel;)I",
363 (void *)com_droidlogic_app_tv_TvControlManager_processCmd
364 },
365 {
366 "addCallbackBuffer",
367 "([B)V",
368 (void *)com_droidlogic_app_tv_TvControlManager_addCallbackBuffer
369 },
370 {
371 "reconnect",
372 "()V",
373 (void *)com_droidlogic_app_tv_TvControlManager_reconnect
374 },
375 {
376 "lock",
377 "()V",
378 (void *)com_droidlogic_app_tv_TvControlManager_lock
379 },
380 {
381 "unlock",
382 "()V",
383 (void *)com_droidlogic_app_tv_TvControlManager_unlock
384 },
385 {
386 "native_create_subtitle_bitmap",
387 "(Ljava/lang/Object;)V",
388 (void *)com_droidlogic_app_tv_TvControlManager_create_subtitle_bitmap
389 },
390 {
391 "native_create_video_frame_bitmap",
392 "(Ljava/lang/Object;)V",
393 (void *)com_droidlogic_app_tv_TvControlManager_create_video_frame_bitmap
394 },
395
396};
397
398struct field {
399 const char *class_name;
400 const char *field_name;
401 const char *field_type;
402 jfieldID *jfield;
403};
404
405static int find_fields(JNIEnv *env, field *fields, int count)
406{
407 for (int i = 0; i < count; i++) {
408 field *f = &fields[i];
409 jclass clazz = env->FindClass(f->class_name);
410 if (clazz == NULL) {
411 ALOGE("Can't find %s", f->class_name);
412 return -1;
413 }
414
415 jfieldID field = env->GetFieldID(clazz, f->field_name, f->field_type);
416 if (field == NULL) {
417 ALOGE("Can't find %s.%s", f->class_name, f->field_name);
418 return -1;
419 }
420
421 *(f->jfield) = field;
422 }
423
424 return 0;
425}
426
427// Get all the required offsets in java class and register native functions
428int register_com_droidlogic_app_tv_TvControlManager(JNIEnv *env)
429{
430 field fields_to_find[] = {
431 { "com/droidlogic/app/tv/TvControlManager", "mNativeContext", "I", &fields.context }
432 };
433
434 ALOGD("register_com_droidlogic_app_tv_TvControlManager.");
435
436 if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
437 return -1;
438
439 jclass clazz = env->FindClass("com/droidlogic/app/tv/TvControlManager");
440 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;ILandroid/os/Parcel;)V");
441 if (fields.post_event == NULL) {
442 ALOGE("Can't find com/droidlogic/app/tv/TvControlManager.postEventFromNative");
443 return -1;
444 }
445
446 // Register native functions
447 return AndroidRuntime::registerNativeMethods(env, "com/droidlogic/app/tv/TvControlManager", camMethods, NELEM(camMethods));
448}
449
450
451jint JNI_OnLoad(JavaVM *vm, void *reserved __unused)
452{
453 JNIEnv *env = NULL;
454 jint result = -1;
455
456 if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
457 ALOGE("ERROR: GetEnv failed\n");
458 goto bail;
459 }
460 assert(env != NULL);
461
462 register_com_droidlogic_app_tv_TvControlManager(env);
463
464 /* success -- return valid version number */
465 result = JNI_VERSION_1_4;
466bail:
467 return result;
468}
469
470