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