1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "image_receiver_napi.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "image_log.h"
20 #include "image_napi_utils.h"
21 #include "image_napi.h"
22 #include "image_receiver_context.h"
23 #include "image_receiver_manager.h"
24 
25 #undef LOG_DOMAIN
26 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
27 
28 #undef LOG_TAG
29 #define LOG_TAG "ImageReceiverNapi"
30 
31 using std::string;
32 using std::shared_ptr;
33 using std::unique_ptr;
34 using std::vector;
35 using std::make_shared;
36 using std::make_unique;
37 
38 namespace OHOS {
39 namespace Media {
40 static const std::string CLASS_NAME = "ImageReceiver";
41 static const std::string DEVICE_ERRCODE = "001";
42 shared_ptr<ImageReceiver> ImageReceiverNapi::staticInstance_ = nullptr;
43 thread_local napi_ref ImageReceiverNapi::sConstructor_ = nullptr;
44 using SurfaceListener = SurfaceBufferAvaliableListener;
45 
46 const int ARGS0 = 0;
47 const int ARGS1 = 1;
48 const int ARGS2 = 2;
49 const int ARGS3 = 3;
50 const int ARGS4 = 4;
51 const int PARAM0 = 0;
52 const int PARAM1 = 1;
53 const int PARAM2 = 2;
54 const int PARAM3 = 3;
55 
56 struct ImageEnum {
57     std::string name;
58     int32_t numVal;
59     std::string strVal;
60 };
61 
62 static std::vector<struct ImageEnum> sImageFormatMap = {
63     {"CAMERA_APP_INNER", 4, ""},
64     {"JPEG", 2000, ""},
65 };
66 
ImageReceiverNapi()67 ImageReceiverNapi::ImageReceiverNapi():env_(nullptr)
68 {}
69 
~ImageReceiverNapi()70 ImageReceiverNapi::~ImageReceiverNapi()
71 {
72     release();
73 }
74 
CommonCallbackRoutine(napi_env env,Context & context,const napi_value & valueParam,bool isRelease=true)75 static void CommonCallbackRoutine(napi_env env, Context &context, const napi_value &valueParam, bool isRelease = true)
76 {
77     IMAGE_FUNCTION_IN();
78     napi_value result[2] = {0};
79     napi_value retVal;
80     napi_value callback = nullptr;
81 
82     napi_get_undefined(env, &result[0]);
83     napi_get_undefined(env, &result[1]);
84 
85     if (context == nullptr) {
86         IMAGE_ERR("context is nullptr");
87         return;
88     }
89 
90     if (context->status == SUCCESS) {
91         result[1] = valueParam;
92     }
93 
94     if (context->deferred) {
95         if (context->status == SUCCESS) {
96             napi_resolve_deferred(env, context->deferred, result[1]);
97         } else {
98             napi_reject_deferred(env, context->deferred, result[0]);
99         }
100     } else {
101         napi_create_uint32(env, context->status, &result[0]);
102         napi_get_reference_value(env, context->callbackRef, &callback);
103         napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
104     }
105 
106     if (isRelease) {
107         if (context->callbackRef != nullptr) {
108             napi_delete_reference(env, context->callbackRef);
109             context->callbackRef = nullptr;
110         }
111 
112         napi_delete_async_work(env, context->work);
113 
114         delete context;
115         context = nullptr;
116     }
117     IMAGE_FUNCTION_OUT();
118 }
119 
NativeRelease()120 void ImageReceiverNapi::NativeRelease()
121 {
122     imageReceiver_ = nullptr;
123 }
124 
UnRegisterReceiverListener()125 void ImageReceiverNapi::UnRegisterReceiverListener()
126 {
127     if (imageReceiver_ != nullptr) {
128         imageReceiver_->UnRegisterBufferAvaliableListener();
129     }
130 }
131 
GetNative()132 ImageReceiver* ImageReceiverNapi::GetNative()
133 {
134     if (imageReceiver_ != nullptr) {
135         return imageReceiver_.get();
136     }
137     return nullptr;
138 }
Init(napi_env env,napi_value exports)139 napi_value ImageReceiverNapi::Init(napi_env env, napi_value exports)
140 {
141     IMAGE_FUNCTION_IN();
142     napi_property_descriptor props[] = {
143         DECLARE_NAPI_FUNCTION("getReceivingSurfaceId", JsGetReceivingSurfaceId),
144         DECLARE_NAPI_FUNCTION("readLatestImage", JsReadLatestImage),
145         DECLARE_NAPI_FUNCTION("readNextImage", JsReadNextImage),
146         DECLARE_NAPI_FUNCTION("on", JsOn),
147         DECLARE_NAPI_FUNCTION("off", JsOff),
148         DECLARE_NAPI_FUNCTION("release", JsRelease),
149 #ifdef IMAGE_DEBUG_FLAG
150         DECLARE_NAPI_GETTER("test", JsTest),
151         DECLARE_NAPI_GETTER("checkDeviceTest", JsCheckDeviceTest),
152         DECLARE_NAPI_GETTER("testYUV", JsTestYUV),
153 #endif
154         DECLARE_NAPI_GETTER("size", JsGetSize),
155         DECLARE_NAPI_GETTER("capacity", JsGetCapacity),
156         DECLARE_NAPI_GETTER("format", JsGetFormat),
157     };
158     napi_property_descriptor static_prop[] = {
159         DECLARE_NAPI_STATIC_FUNCTION("createImageReceiver", JSCreateImageReceiver),
160     };
161 
162     napi_value constructor = nullptr;
163     size_t props_count = IMG_ARRAY_SIZE(props);
164     size_t static_props_count = IMG_ARRAY_SIZE(static_prop);
165 
166     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
167         napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor,
168         nullptr, props_count, props, &constructor)),
169         nullptr,
170         IMAGE_ERR("define class fail")
171     );
172 
173     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
174         napi_create_reference(env, constructor, 1, &sConstructor_)),
175         nullptr,
176         IMAGE_ERR("create reference fail")
177     );
178 
179     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
180         napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
181         nullptr,
182         IMAGE_ERR("set named property fail")
183     );
184     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
185         napi_define_properties(env, exports, static_props_count, static_prop)),
186         nullptr,
187         IMAGE_ERR("define properties fail")
188     );
189 
190     IMAGE_DEBUG("Init success");
191 
192     IMAGE_FUNCTION_OUT();
193     return exports;
194 }
195 
196 struct ImageReceiverInputArgs {
197     napi_value thisVar;
198     size_t argc;
199     napi_value argv[ARGS4];
200     int32_t args[ARGS4];
201 };
202 
parseImageReceiverArgs(napi_env env,napi_callback_info info,ImageReceiverInputArgs & args,std::string & errMsg)203 static bool parseImageReceiverArgs(napi_env env, napi_callback_info info,
204     ImageReceiverInputArgs &args, std::string &errMsg)
205 {
206     napi_status status = napi_get_cb_info(env, info, &(args.argc), args.argv, &(args.thisVar), nullptr);
207     if (status != napi_ok) {
208         IMAGE_ERR("fail to napi_get_cb_info %{public}d", status);
209         errMsg = "Fail to napi_get_cb_info";
210         return false;
211     }
212 
213     if (args.argc != ARGS3 && args.argc != ARGS4) {
214         errMsg = "Invalid arg counts ";
215         errMsg.append(std::to_string(args.argc));
216         return false;
217     }
218 
219     return ImageNapiUtils::ParseImageCreatorReceiverArgs(env, args.argc, args.argv, args.args, errMsg);
220 }
221 
Constructor(napi_env env,napi_callback_info info)222 napi_value ImageReceiverNapi::Constructor(napi_env env, napi_callback_info info)
223 {
224     napi_value undefineVar = nullptr;
225     napi_get_undefined(env, &undefineVar);
226 
227     IMAGE_FUNCTION_IN();
228     std::string errMsg;
229     ImageReceiverInputArgs inputArgs;
230     inputArgs.argc = ARGS4;
231     if (!parseImageReceiverArgs(env, info, inputArgs, errMsg) || inputArgs.thisVar == nullptr) {
232         IMAGE_ERR("Failure. %{public}s", errMsg.c_str());
233         return undefineVar;
234     }
235     auto reference = std::make_unique<ImageReceiverNapi>();
236     reference->env_ = env;
237     reference->imageReceiver_ = ImageReceiver::CreateImageReceiver((inputArgs.args)[PARAM0],
238         (inputArgs.args)[PARAM1], (inputArgs.args)[PARAM2], (inputArgs.args)[PARAM3]);
239     if (reference->imageReceiver_ == nullptr) {
240         IMAGE_ERR("Create native image receiver failed");
241         return undefineVar;
242     }
243     napi_status status = napi_wrap(env, inputArgs.thisVar, reinterpret_cast<void *>(reference.get()),
244         ImageReceiverNapi::Destructor, nullptr, nullptr);
245     if (status == napi_ok) {
246         reference.release();
247         return inputArgs.thisVar;
248     }
249     IMAGE_ERR("Failure wrapping js to native napi");
250     return undefineVar;
251 }
252 
Destructor(napi_env env,void * nativeObject,void * finalize)253 void ImageReceiverNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
254 {
255     if (nativeObject != nullptr) {
256         delete reinterpret_cast<ImageReceiverNapi*>(nativeObject);
257         nativeObject = nullptr;
258     }
259 }
260 
checkFormat(int32_t format)261 static bool checkFormat(int32_t format)
262 {
263     for (auto imgEnum : sImageFormatMap) {
264         if (imgEnum.numVal == format) {
265             return true;
266         }
267     }
268     return false;
269 }
270 
CreateImageReceiverJsObject(napi_env env,struct ImageReceiverCreateArgs args)271 napi_value ImageReceiverNapi::CreateImageReceiverJsObject(napi_env env, struct ImageReceiverCreateArgs args)
272 {
273     napi_status status;
274     napi_value constructor = nullptr;
275     napi_value result = nullptr;
276     ImageReceiverInputArgs inputArgs;
277     inputArgs.argc = ARGS4;
278 
279     IMAGE_FUNCTION_IN();
280     if (!checkFormat(args.format)) {
281         IMAGE_ERR("Invalid type");
282         return nullptr;
283     }
284     napi_create_int32(env, args.width, &(inputArgs.argv[PARAM0]));
285     napi_create_int32(env, args.height, &(inputArgs.argv[PARAM1]));
286     napi_create_int32(env, args.format, &(inputArgs.argv[PARAM2]));
287     napi_create_int32(env, args.capicity, &(inputArgs.argv[PARAM3]));
288     status = napi_get_reference_value(env, sConstructor_, &constructor);
289     if (status != napi_ok || constructor == nullptr) {
290         IMAGE_ERR("Failed to get reference of constructor");
291         return nullptr;
292     }
293 
294     status = napi_new_instance(env, constructor, inputArgs.argc, inputArgs.argv, &result);
295     if (status != napi_ok || result == nullptr) {
296         IMAGE_ERR("New instance could not be obtained");
297         return nullptr;
298     }
299 
300     IMAGE_FUNCTION_OUT();
301     return result;
302 }
303 
JSCreateImageReceiver(napi_env env,napi_callback_info info)304 napi_value ImageReceiverNapi::JSCreateImageReceiver(napi_env env, napi_callback_info info)
305 {
306     napi_status status;
307     napi_value constructor = nullptr;
308     napi_value result = nullptr;
309     ImageReceiverInputArgs inputArgs;
310     inputArgs.argc = ARGS4;
311 
312     IMAGE_FUNCTION_IN();
313     napi_get_undefined(env, &result);
314 
315     std::string errMsg;
316     if (!parseImageReceiverArgs(env, info, inputArgs, errMsg)) {
317         return ImageNapiUtils::ThrowExceptionError(env, COMMON_ERR_INVALID_PARAMETER, errMsg);
318     }
319 
320     if (!checkFormat(inputArgs.args[PARAM2])) {
321         return ImageNapiUtils::ThrowExceptionError(env, COMMON_ERR_INVALID_PARAMETER, "Invalid type");
322     }
323 
324     status = napi_get_reference_value(env, sConstructor_, &constructor);
325     if (IMG_IS_OK(status)) {
326         status = napi_new_instance(env, constructor, inputArgs.argc, inputArgs.argv, &result);
327         if (status == napi_ok) {
328             IMAGE_FUNCTION_OUT();
329             return result;
330         } else {
331             IMAGE_ERR("New instance could not be obtained");
332         }
333     }
334 
335     IMAGE_ERR("Failed to get reference of constructor");
336     return result;
337 }
338 
CheckArgs(const ImageReceiverCommonArgs & args)339 static bool CheckArgs(const ImageReceiverCommonArgs &args)
340 {
341     if (args.async != CallType::GETTER) {
342         if (args.queryArgs == nullptr) {
343             IMAGE_ERR("No query args function");
344             return false;
345         }
346     }
347 
348     if (args.async != CallType::ASYNC || args.asyncLater) {
349         if (args.nonAsyncBack == nullptr) {
350             IMAGE_ERR("No non async back function");
351             return false;
352         }
353     }
354     return true;
355 }
356 
PrepareOneArg(ImageReceiverCommonArgs & args,struct ImageReceiverInnerContext & ic)357 static bool PrepareOneArg(ImageReceiverCommonArgs &args, struct ImageReceiverInnerContext &ic)
358 {
359     if (ic.argc == ARGS1) {
360         auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
361         if (argType == napi_function) {
362             napi_create_reference(args.env, ic.argv[PARAM0], ic.refCount, &(ic.context->callbackRef));
363         } else {
364             IMAGE_ERR("Unsupport arg 0 type: %{public}d", argType);
365             return false;
366         }
367     }
368 
369     if (ic.context->callbackRef == nullptr) {
370         napi_create_promise(args.env, &(ic.context->deferred), &(ic.result));
371     } else {
372         napi_get_undefined(args.env, &ic.result);
373     }
374     return true;
375 }
376 
JSCommonProcess(ImageReceiverCommonArgs & args)377 napi_value ImageReceiverNapi::JSCommonProcess(ImageReceiverCommonArgs &args)
378 {
379     IMAGE_FUNCTION_IN();
380     struct ImageReceiverInnerContext ic;
381     ic.argc = args.argc;
382     ic.argv.resize(ic.argc);
383     napi_get_undefined(args.env, &ic.result);
384 
385     IMG_NAPI_CHECK_RET(CheckArgs(args), ic.result);
386 
387     IMG_JS_ARGS(args.env, args.info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
388 
389     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
390 
391     if (args.async != CallType::STATIC) {
392         ic.context = std::make_unique<ImageReceiverAsyncContext>();
393         if (ic.context == nullptr) {
394             return ic.result;
395         }
396         ic.status = napi_unwrap(args.env, ic.thisVar, reinterpret_cast<void**>(&(ic.context->constructor_)));
397 
398         IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->constructor_),
399             ic.result, IMAGE_ERR("fail to unwrap context"));
400 
401         if (ic.context->constructor_ == nullptr) {
402             return ic.result;
403         }
404 
405         IMG_NAPI_CHECK_RET_D(IMG_IS_READY(ic.status, ic.context->constructor_->imageReceiver_),
406             ic.result, IMAGE_ERR("empty native receiver"));
407     }
408     if (args.async != CallType::GETTER) {
409         if (!args.queryArgs(args, ic)) {
410             return ic.result;
411         }
412     }
413 
414     if (args.async == CallType::ASYNC) {
415         if (args.asyncLater) {
416             args.nonAsyncBack(args, ic);
417         } else {
418             napi_value _resource = nullptr;
419             napi_create_string_utf8((args.env), (args.name.c_str()), NAPI_AUTO_LENGTH, &_resource);
420             (ic.status) = napi_create_async_work(args.env, nullptr, _resource,
421                                                  ([](napi_env env, void *data) {}),
422                                                  (reinterpret_cast<napi_async_complete_callback>(args.callBack)),
423                                                  static_cast<void *>((ic.context).get()), &(ic.context->work));
424             napi_queue_async_work((args.env), (ic.context->work));
425             ic.context.release();
426         }
427     } else {
428         args.nonAsyncBack(args, ic);
429     }
430 
431     IMAGE_FUNCTION_OUT();
432     return ic.result;
433 }
434 
BuildJsSize(napi_env env,int32_t width,int32_t height)435 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
436 {
437     napi_value result = nullptr;
438     napi_value sizeWith = nullptr;
439     napi_value sizeHeight = nullptr;
440 
441     napi_create_object(env, &result);
442 
443     napi_create_int32(env, width, &sizeWith);
444     napi_set_named_property(env, result, "width", sizeWith);
445 
446     napi_create_int32(env, height, &sizeHeight);
447     napi_set_named_property(env, result, "height", sizeHeight);
448     return result;
449 }
450 
JsGetSize(napi_env env,napi_callback_info info)451 napi_value ImageReceiverNapi::JsGetSize(napi_env env, napi_callback_info info)
452 {
453     IMAGE_FUNCTION_IN();
454     ImageReceiverCommonArgs args = {
455         .env = env, .info = info,
456         .async = CallType::GETTER,
457     };
458     args.argc = ARGS0;
459 
460     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
461         napi_get_undefined(args.env, &(ic.result));
462         auto native = ic.context->constructor_->imageReceiver_;
463         if (native == nullptr) {
464             IMAGE_ERR("Native instance is nullptr");
465             return false;
466         }
467 
468         if (native->iraContext_ == nullptr) {
469             IMAGE_ERR("Image receiver context is nullptr");
470             return false;
471         }
472         ic.result = BuildJsSize(args.env,
473                                 native->iraContext_->GetWidth(),
474                                 native->iraContext_->GetHeight());
475         return true;
476     };
477 
478     return JSCommonProcess(args);
479 }
480 
JsGetCapacity(napi_env env,napi_callback_info info)481 napi_value ImageReceiverNapi::JsGetCapacity(napi_env env, napi_callback_info info)
482 {
483     IMAGE_FUNCTION_IN();
484     ImageReceiverCommonArgs args = {
485         .env = env, .info = info,
486         .async = CallType::GETTER,
487     };
488     args.argc = ARGS0;
489 
490     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
491         napi_get_undefined(args.env, &(ic.result));
492         auto native = ic.context->constructor_->imageReceiver_;
493         if (native == nullptr) {
494             IMAGE_ERR("Native instance is nullptr");
495             return false;
496         }
497 
498         if (native->iraContext_ == nullptr) {
499             IMAGE_ERR("Image receiver context is nullptr");
500             return false;
501         }
502         napi_create_int32(args.env, native->iraContext_->GetCapicity(), &(ic.result));
503         return true;
504     };
505 
506     return JSCommonProcess(args);
507 }
508 
JsGetFormat(napi_env env,napi_callback_info info)509 napi_value ImageReceiverNapi::JsGetFormat(napi_env env, napi_callback_info info)
510 {
511     IMAGE_FUNCTION_IN();
512     ImageReceiverCommonArgs args = {
513         .env = env, .info = info,
514         .async = CallType::GETTER,
515     };
516     args.argc = ARGS0;
517 
518     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
519         napi_get_undefined(args.env, &(ic.result));
520         auto native = ic.context->constructor_->imageReceiver_;
521         if (native == nullptr) {
522             IMAGE_ERR("Native instance is nullptr");
523             return false;
524         }
525 
526         if (native->iraContext_ == nullptr) {
527             IMAGE_ERR("Image receiver context is nullptr");
528             return false;
529         }
530         napi_create_int32(args.env, native->iraContext_->GetFormat(), &(ic.result));
531         return true;
532     };
533 
534     return JSCommonProcess(args);
535 }
536 
537 #ifdef IMAGE_DEBUG_FLAG
TestRequestBuffer(OHOS::sptr<OHOS::Surface> & receiverSurface,OHOS::BufferRequestConfig requestConfig,OHOS::BufferFlushConfig flushConfig)538 static void TestRequestBuffer(OHOS::sptr<OHOS::Surface> &receiverSurface,
539                               OHOS::BufferRequestConfig requestConfig,
540                               OHOS::BufferFlushConfig flushConfig)
541 {
542     OHOS::sptr<OHOS::SurfaceBuffer> buffer;
543     int32_t releaseFence;
544     if (receiverSurface == nullptr) {
545         IMAGE_ERR("Image receiver receiverSurface is nullptr");
546         return;
547     }
548     requestConfig.width = receiverSurface->GetDefaultWidth();
549     requestConfig.height = receiverSurface->GetDefaultHeight();
550     receiverSurface->RequestBuffer(buffer, releaseFence, requestConfig);
551     if (buffer == nullptr) {
552         IMAGE_ERR("Image receiver buffer is nullptr");
553         return;
554     }
555     IMAGE_ERR("RequestBuffer");
556     int32_t *p = reinterpret_cast<int32_t *>(buffer->GetVirAddr());
557     int32_t size = static_cast<int32_t>(buffer->GetSize() / 4);
558     if (p != nullptr) {
559         for (int32_t i = 0; i < size; i++) {
560             p[i] = i;
561         }
562     }
563     receiverSurface->FlushBuffer(buffer, -1, flushConfig);
564     IMAGE_ERR("FlushBuffer");
565 }
566 
DoTest(std::shared_ptr<ImageReceiver> imageReceiver,int pixelFormat)567 static void DoTest(std::shared_ptr<ImageReceiver> imageReceiver, int pixelFormat)
568 {
569     OHOS::BufferRequestConfig requestConfig = {
570         .width = 0x100,
571         .height = 0x100,
572         .strideAlignment = 0x8,
573         .format = pixelFormat,
574         .usage = HBM_USE_CPU_READ | HBM_USE_CPU_WRITE | HBM_USE_MEM_DMA,
575         .timeout = 0,
576     };
577 
578     OHOS::BufferFlushConfig flushConfig = {
579         .damage = {
580             .w = 0x100,
581             .h = 0x100,
582         },
583     };
584 
585     if (imageReceiver == nullptr || imageReceiver->iraContext_ == nullptr) {
586         IMAGE_ERR("Image receiver DoTest imageReceiver is nullptr");
587         return;
588     }
589     std::string receiveKey = imageReceiver->iraContext_->GetReceiverKey();
590     IMAGE_ERR("ReceiverKey = %{public}s", receiveKey.c_str());
591     OHOS::sptr<OHOS::Surface> receiverSurface = ImageReceiver::getSurfaceById(receiveKey);
592     if (receiverSurface == nullptr) {
593         IMAGE_ERR("Image receiver DoTest receiverSurface is nullptr");
594         return;
595     }
596     IMAGE_ERR("getDefaultWidth = %{public}d", receiverSurface->GetDefaultWidth());
597     IMAGE_ERR("getDefaultHeight = %{public}d", receiverSurface->GetDefaultHeight());
598     IMAGE_ERR("TestRequestBuffer 1 ...");
599     TestRequestBuffer(receiverSurface, requestConfig, flushConfig);
600     IMAGE_ERR("TestRequestBuffer 2 ...");
601     TestRequestBuffer(receiverSurface, requestConfig, flushConfig);
602     IMAGE_ERR("TestRequestBuffer 3 ...");
603     TestRequestBuffer(receiverSurface, requestConfig, flushConfig);
604 }
605 
JsTest(napi_env env,napi_callback_info info)606 napi_value ImageReceiverNapi::JsTest(napi_env env, napi_callback_info info)
607 {
608     IMAGE_FUNCTION_IN();
609     ImageReceiverCommonArgs args = {
610         .env = env, .info = info,
611         .async = CallType::GETTER,
612     };
613     args.argc = ARGS0;
614 
615     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
616         ic.context->constructor_->isCallBackTest = true;
617         DoTest(ic.context->constructor_->imageReceiver_, PIXEL_FMT_RGBA_8888);
618         return true;
619     };
620 
621     return JSCommonProcess(args);
622 }
623 
JsCheckDeviceTest(napi_env env,napi_callback_info info)624 napi_value ImageReceiverNapi::JsCheckDeviceTest(napi_env env, napi_callback_info info)
625 {
626     IMAGE_FUNCTION_IN();
627     ImageReceiverCommonArgs args = {
628         .env = env, .info = info,
629         .async = CallType::GETTER,
630     };
631     args.argc = ARGS0;
632 
633     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
634         napi_get_undefined(args.env, &(ic.result));
635         napi_value mess = nullptr;
636         ic.context->constructor_->isCallBackTest = true;
637         napi_create_string_utf8(args.env, DEVICE_ERRCODE.c_str(), NAPI_AUTO_LENGTH, &mess);
638         ic.result = mess;
639         if (args.async != CallType::GETTER) {
640             DoTest(ic.context->constructor_->imageReceiver_, PIXEL_FMT_RGBA_8888);
641         }
642         return true;
643     };
644 
645     return JSCommonProcess(args);
646 }
647 
JsTestYUV(napi_env env,napi_callback_info info)648 napi_value ImageReceiverNapi::JsTestYUV(napi_env env, napi_callback_info info)
649 {
650     IMAGE_FUNCTION_IN();
651     ImageReceiverCommonArgs args = {
652         .env = env, .info = info,
653         .async = CallType::GETTER,
654     };
655     args.argc = ARGS0;
656 
657     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
658         ic.context->constructor_->isCallBackTest = true;
659         DoTest(ic.context->constructor_->imageReceiver_, PIXEL_FMT_YCBCR_422_SP);
660         return true;
661     };
662 
663     return JSCommonProcess(args);
664 }
665 #endif
666 
JsGetReceivingSurfaceId(napi_env env,napi_callback_info info)667 napi_value ImageReceiverNapi::JsGetReceivingSurfaceId(napi_env env, napi_callback_info info)
668 {
669     IMAGE_FUNCTION_IN();
670     ImageReceiverCommonArgs args = {
671         .env = env, .info = info,
672         .async = CallType::ASYNC,
673         .name = "JsGetReceivingSurfaceId",
674         .callBack = nullptr,
675         .argc = ARGS1,
676         .queryArgs = PrepareOneArg,
677     };
678 
679     args.callBack = [](napi_env env, napi_status status, Context context) {
680         IMAGE_LINE_IN();
681         napi_value result = nullptr;
682         napi_get_undefined(env, &result);
683 
684         auto native = context->constructor_->imageReceiver_;
685         if (native == nullptr) {
686             IMAGE_ERR("Native instance is nullptr");
687             context->status = ERR_IMAGE_INIT_ABNORMAL;
688         } else if (native->iraContext_ == nullptr) {
689             IMAGE_ERR("Image receiver context is nullptr");
690             context->status = ERR_IMAGE_INIT_ABNORMAL;
691         } else {
692             napi_create_string_utf8(env, native->iraContext_->GetReceiverKey().c_str(),
693                                     NAPI_AUTO_LENGTH, &result);
694             context->status = SUCCESS;
695         }
696 
697         IMAGE_LINE_OUT();
698         CommonCallbackRoutine(env, context, result);
699     };
700 
701     return JSCommonProcess(args);
702 }
703 
704 #ifdef IMAGE_SAVE_BUFFER_TO_PIC
DoCallBackTest(OHOS::sptr<OHOS::SurfaceBuffer> surfaceBuffer1)705 static void DoCallBackTest(OHOS::sptr<OHOS::SurfaceBuffer> surfaceBuffer1)
706 {
707     if (surfaceBuffer1 == nullptr) {
708         IMAGE_ERR("surfaceBuffer1 is null");
709         return;
710     }
711 
712     ImageReceiverManager& imageReceiverManager = ImageReceiverManager::getInstance();
713     shared_ptr<ImageReceiver> imageReceiver1 = imageReceiverManager.getImageReceiverByKeyId("1");
714     if (imageReceiver1 == nullptr || imageReceiver1->iraContext_ == nullptr) {
715         return;
716     }
717     IMAGE_ERR("DoCallBackTest format %{public}d", imageReceiver1->iraContext_->GetFormat());
718 
719     InitializationOptions opts;
720     opts.size.width = surfaceBuffer1->GetWidth();
721     opts.size.height = surfaceBuffer1->GetHeight();
722     opts.pixelFormat = OHOS::Media::PixelFormat::BGRA_8888;
723     opts.alphaType = OHOS::Media::AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN;
724     opts.scaleMode = OHOS::Media::ScaleMode::CENTER_CROP;
725     opts.editable = true;
726     IMAGE_ERR("DoCallBackTest Width %{public}d", opts.size.width);
727     IMAGE_ERR("DoCallBackTest Height %{public}d", opts.size.height);
728     int fd = open("/data/receiver/test.jpg", O_RDWR | O_CREAT);
729     imageReceiver1->SaveBufferAsImage(fd, surfaceBuffer1, opts);
730 }
731 #endif
FailedCallbackRoutine(napi_env env,Context & context,uint32_t errCode)732 static void FailedCallbackRoutine(napi_env env, Context &context, uint32_t errCode)
733 {
734     napi_value result = nullptr;
735     napi_get_undefined(env, &result);
736     if (context != nullptr) {
737         context->status = ERR_IMAGE_INIT_ABNORMAL;
738     }
739     CommonCallbackRoutine(env, context, result);
740 }
JsReadLatestImage(napi_env env,napi_callback_info info)741 napi_value ImageReceiverNapi::JsReadLatestImage(napi_env env, napi_callback_info info)
742 {
743     IMAGE_FUNCTION_IN();
744     ImageReceiverCommonArgs args = {
745         .env = env, .info = info,
746         .async = CallType::ASYNC,
747         .name = "JsReadLatestImage",
748         .callBack = nullptr,
749         .argc = ARGS1,
750         .queryArgs = PrepareOneArg,
751     };
752 
753     args.callBack = [](napi_env env, napi_status status, Context context) {
754         IMAGE_LINE_IN();
755         auto native = context->constructor_->imageReceiver_;
756         if (native == nullptr) {
757             IMAGE_ERR("Native instance is nullptr");
758             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
759             return;
760         }
761         auto image = native->LastNativeImage();
762         if (image == nullptr) {
763             IMAGE_ERR("LastNativeImage is nullptr");
764             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
765             return;
766         }
767 #ifdef IMAGE_DEBUG_FLAG
768         if (context->constructor_->isCallBackTest) {
769             context->constructor_->isCallBackTest = false;
770 #ifdef IMAGE_SAVE_BUFFER_TO_PIC
771             DoCallBackTest(image->GetBuffer());
772 #endif
773         }
774 #endif
775         napi_value result = ImageNapi::Create(env, image);
776         if (result == nullptr) {
777             IMAGE_ERR("ImageNapi Create is nullptr");
778             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
779             return;
780         }
781         context->status = SUCCESS;
782         IMAGE_LINE_OUT();
783         CommonCallbackRoutine(env, context, result);
784     };
785 
786     return JSCommonProcess(args);
787 }
788 
JsReadNextImage(napi_env env,napi_callback_info info)789 napi_value ImageReceiverNapi::JsReadNextImage(napi_env env, napi_callback_info info)
790 {
791     IMAGE_FUNCTION_IN();
792     ImageReceiverCommonArgs args = {
793         .env = env, .info = info,
794         .async = CallType::ASYNC,
795         .name = "JsReadNextImage",
796         .callBack = nullptr,
797         .argc = ARGS1,
798         .queryArgs = PrepareOneArg,
799     };
800 
801     args.callBack = [](napi_env env, napi_status status, Context context) {
802         IMAGE_LINE_IN();
803         auto native = context->constructor_->imageReceiver_;
804         if (native == nullptr) {
805             IMAGE_ERR("Native instance is nullptr");
806             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
807             return;
808         }
809         auto image = native->NextNativeImage();
810         if (image == nullptr) {
811             IMAGE_ERR("NextNativeImage is nullptr");
812             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
813             return;
814         }
815 #ifdef IMAGE_DEBUG_FLAG
816         if (context->constructor_->isCallBackTest) {
817             context->constructor_->isCallBackTest = false;
818 #ifdef IMAGE_SAVE_BUFFER_TO_PIC
819             DoCallBackTest(image->GetBuffer());
820 #endif
821         }
822 #endif
823         napi_value result = ImageNapi::Create(env, image);
824         if (result == nullptr) {
825             IMAGE_ERR("ImageNapi Create is nullptr");
826             FailedCallbackRoutine(env, context, ERR_IMAGE_INIT_ABNORMAL);
827             return;
828         }
829         context->status = SUCCESS;
830         IMAGE_LINE_OUT();
831         CommonCallbackRoutine(env, context, result);
832     };
833 
834     return JSCommonProcess(args);
835 }
836 
CheckOnParam0(napi_env env,napi_value value,const std::string & refStr)837 static bool CheckOnParam0(napi_env env, napi_value value, const std::string& refStr)
838 {
839     bool ret = true;
840     size_t bufLength = 0;
841     napi_status status = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
842     if (status != napi_ok || bufLength > PATH_MAX) {
843         return false;
844     }
845 
846     char *buffer = static_cast<char *>(malloc((bufLength + 1) * sizeof(char)));
847     if (buffer == nullptr) {
848         return false;
849     }
850 
851     status = napi_get_value_string_utf8(env, value, buffer, bufLength + 1, &bufLength);
852     if (status != napi_ok) {
853         ret = false;
854     } else {
855         std::string strValue = buffer;
856         if (strValue.compare(refStr) != 0) {
857             IMAGE_ERR("strValue is %{public}s", strValue.c_str());
858             ret = false;
859         }
860     }
861 
862     free(buffer);
863     buffer = nullptr;
864     return ret;
865 }
866 
JsOnQueryArgs(ImageReceiverCommonArgs & args,ImageReceiverInnerContext & ic)867 static bool JsOnQueryArgs(ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic)
868 {
869     if (ic.argc == ARGS2) {
870         auto argType0 = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
871         auto argType1 = ImageNapiUtils::getType(args.env, ic.argv[PARAM1]);
872         if (argType0 == napi_string && argType1 == napi_function) {
873             if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
874                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
875                     "Could not get On type string");
876                 return false;
877             }
878 
879             if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageArrival")) {
880                 ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
881                     "Unsupport PARAM0");
882                 return false;
883             }
884 
885             napi_create_reference(args.env, ic.argv[PARAM1], ic.refCount, &(ic.context->callbackRef));
886         } else {
887             std::string errMsg = "Unsupport args type: ";
888             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
889                 errMsg.append(std::to_string(argType0)).append(std::to_string(argType1)));
890             return false;
891         }
892     } else {
893         std::string errMsg = "Invalid argc: ";
894         ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
895             errMsg.append(std::to_string(ic.argc)));
896         return false;
897     }
898 
899     napi_get_undefined(args.env, &ic.result);
900     return true;
901 }
902 
Callback(uv_work_t * work,int status)903 static void Callback(uv_work_t *work, int status)
904 {
905     IMAGE_LINE_IN();
906     Context context = reinterpret_cast<Context>(work->data);
907     if (context == nullptr) {
908         IMAGE_ERR("context is empty");
909     } else {
910         if (context->env != nullptr && context->callbackRef != nullptr) {
911             napi_handle_scope scope = nullptr;
912             napi_open_handle_scope(context->env, &scope);
913             napi_value result[PARAM2] = {0};
914             napi_value retVal;
915             napi_value callback = nullptr;
916             if (scope == nullptr) {
917                 delete work;
918                 return;
919             }
920             napi_create_uint32(context->env, SUCCESS, &result[0]);
921             napi_get_undefined(context->env, &result[1]);
922             napi_get_reference_value(context->env, context->callbackRef, &callback);
923             if (callback != nullptr) {
924                 napi_call_function(context->env, nullptr, callback, PARAM2, result, &retVal);
925             } else {
926                 IMAGE_ERR("napi_get_reference_value callback is empty");
927             }
928             napi_close_handle_scope(context->env, scope);
929         } else {
930             IMAGE_ERR("env or callbackRef is empty");
931         }
932     }
933     delete work;
934     IMAGE_LINE_OUT();
935 }
936 
DoCallBack(shared_ptr<ImageReceiverAsyncContext> & context,string name,CompleteCallback callBack)937 void ImageReceiverNapi::DoCallBack(shared_ptr<ImageReceiverAsyncContext> &context,
938                                    string name, CompleteCallback callBack)
939 {
940     IMAGE_FUNCTION_IN();
941     auto localContext = std::make_unique<shared_ptr<ImageReceiverAsyncContext>> (context);
942     if (context == nullptr) {
943         IMAGE_ERR("gContext is empty");
944         localContext.release();
945         return;
946     }
947     if (context->env == nullptr) {
948         IMAGE_ERR("env is empty");
949         localContext.release();
950         return;
951     }
952 
953     uv_loop_s *loop = nullptr;
954     napi_get_uv_event_loop(context->env, &loop);
955     if (loop == nullptr) {
956         IMAGE_ERR("napi_get_uv_event_loop failed");
957         localContext.release();
958         return;
959     }
960 
961     unique_ptr<uv_work_t> work = make_unique<uv_work_t>();
962     if (work == nullptr) {
963         IMAGE_ERR("DoCallBack: No memory");
964         localContext.release();
965         return;
966     }
967     work->data = reinterpret_cast<void *>(context.get());
968     int ret = uv_queue_work(loop, work.get(), [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
969         Callback(work, status);
970     });
971     if (ret != 0) {
972         IMAGE_ERR("Failed to execute DoCallBack work queue");
973     } else {
974         work.release();
975     }
976     localContext.release();
977     IMAGE_FUNCTION_OUT();
978 }
979 
JsOn(napi_env env,napi_callback_info info)980 napi_value ImageReceiverNapi::JsOn(napi_env env, napi_callback_info info)
981 {
982     IMAGE_FUNCTION_IN();
983     ImageReceiverCommonArgs args = {
984         .env = env, .info = info,
985         .async = CallType::ASYNC,
986         .name = "JsOn",
987     };
988     args.argc = ARGS2;
989     args.asyncLater = true;
990     args.queryArgs = JsOnQueryArgs;
991     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
992         IMAGE_LINE_IN();
993         napi_get_undefined(args.env, &(ic.result));
994 
995         auto native = ic.context->constructor_->imageReceiver_;
996         if (native == nullptr) {
997             IMAGE_ERR("Native instance is nullptr");
998             ic.context->status = ERR_IMAGE_INIT_ABNORMAL;
999             return false;
1000         }
1001         shared_ptr<ImageReceiverAvaliableListener> listener = make_shared<ImageReceiverAvaliableListener>();
1002         listener->context = std::move(ic.context);
1003         listener->context->env = args.env;
1004         listener->name = args.name;
1005 
1006         native->RegisterBufferAvaliableListener((std::shared_ptr<SurfaceBufferAvaliableListener> &)listener);
1007 
1008         IMAGE_LINE_OUT();
1009         return true;
1010     };
1011 
1012     return JSCommonProcess(args);
1013 }
1014 
JsOffOneArg(napi_env env,napi_callback_info info)1015 napi_value ImageReceiverNapi::JsOffOneArg(napi_env env, napi_callback_info info)
1016 {
1017     ImageReceiverCommonArgs args = {
1018         .env = env, .info = info, .async = CallType::ASYNC,
1019         .name = "JsOff", .argc = ARGS1, .asyncLater = true,
1020     };
1021 
1022     args.queryArgs = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
1023         if (ic.argc != ARGS1) {
1024             std::string errMsg = "Invalid argc: ";
1025             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
1026                 errMsg.append(std::to_string(ic.argc)));
1027             return false;
1028         }
1029         auto argType = ImageNapiUtils::getType(args.env, ic.argv[PARAM0]);
1030         if (argType != napi_string) {
1031             std::string errMsg = "Unsupport args type: ";
1032             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
1033                 errMsg.append(std::to_string(argType)));
1034             return false;
1035         }
1036         if (!ImageNapiUtils::GetUtf8String(args.env, ic.argv[PARAM0], ic.onType)) {
1037             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
1038                 "Could not get On type string");
1039             return false;
1040         }
1041         if (!CheckOnParam0(args.env, ic.argv[PARAM0], "imageArrival")) {
1042             ImageNapiUtils::ThrowExceptionError(args.env, static_cast<int32_t>(napi_invalid_arg),
1043                 "Unsupport PARAM0");
1044             return false;
1045         }
1046         napi_get_undefined(args.env, &ic.result);
1047         return true;
1048     };
1049 
1050     args.nonAsyncBack = [](ImageReceiverCommonArgs &args, ImageReceiverInnerContext &ic) -> bool {
1051         IMAGE_LINE_IN();
1052         napi_get_undefined(args.env, &ic.result);
1053         ic.context->constructor_->imageReceiver_->UnRegisterBufferAvaliableListener();
1054         ic.context->status = SUCCESS;
1055         napi_create_uint32(args.env, ic.context->status, &ic.result);
1056         IMAGE_LINE_OUT();
1057         return true;
1058     };
1059 
1060     return JSCommonProcess(args);
1061 }
1062 
JsOffTwoArgs(napi_env env,napi_callback_info info)1063 napi_value ImageReceiverNapi::JsOffTwoArgs(napi_env env, napi_callback_info info)
1064 {
1065     napi_value result = nullptr;
1066     napi_get_undefined(env, &result);
1067 
1068     ImageReceiverCommonArgs args = {
1069         .env = env, .info = info, .async = CallType::ASYNC,
1070         .name = "JsOff", .argc = ARGS2, .queryArgs = JsOnQueryArgs,
1071     };
1072 
1073     args.callBack = [](napi_env env, napi_status status, Context context) {
1074         IMAGE_LINE_IN();
1075         napi_value result = nullptr;
1076         napi_get_undefined(env, &result);
1077         context->constructor_->imageReceiver_->UnRegisterBufferAvaliableListener();
1078         context->status = SUCCESS;
1079         IMAGE_LINE_OUT();
1080         CommonCallbackRoutine(env, context, result);
1081     };
1082 
1083     JSCommonProcess(args);
1084     napi_create_uint32(args.env, SUCCESS, &result);
1085     return result;
1086 }
1087 
JsOff(napi_env env,napi_callback_info info)1088 napi_value ImageReceiverNapi::JsOff(napi_env env, napi_callback_info info)
1089 {
1090     IMAGE_FUNCTION_IN();
1091     struct ImageReceiverInnerContext ic;
1092     ic.argc = ARGS2;
1093     ic.argv.resize(ic.argc);
1094     napi_get_undefined(env, &ic.result);
1095     IMG_JS_ARGS(env, info, ic.status, ic.argc, &(ic.argv[0]), ic.thisVar);
1096     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(ic.status), ic.result, IMAGE_ERR("fail to napi_get_cb_info"));
1097 
1098     if (ic.argc == ARGS1) {
1099         return JsOffOneArg(env, info);
1100     } else if (ic.argc == ARGS2) {
1101         return JsOffTwoArgs(env, info);
1102     } else {
1103         IMAGE_ERR("invalid argument count");
1104         return ic.result;
1105     }
1106 }
1107 
JsRelease(napi_env env,napi_callback_info info)1108 napi_value ImageReceiverNapi::JsRelease(napi_env env, napi_callback_info info)
1109 {
1110     IMAGE_FUNCTION_IN();
1111     ImageReceiverCommonArgs args = {
1112         .env = env, .info = info,
1113         .async = CallType::ASYNC,
1114         .name = "JsRelease",
1115         .callBack = nullptr,
1116         .argc = ARGS1,
1117         .queryArgs = PrepareOneArg,
1118     };
1119 
1120     args.callBack = [](napi_env env, napi_status status, Context context) {
1121         IMAGE_LINE_IN();
1122         napi_value result = nullptr;
1123         napi_get_undefined(env, &result);
1124 
1125         context->constructor_->UnRegisterReceiverListener();
1126         context->constructor_->NativeRelease();
1127         context->status = SUCCESS;
1128 
1129         IMAGE_LINE_OUT();
1130         CommonCallbackRoutine(env, context, result);
1131     };
1132 
1133     return JSCommonProcess(args);
1134 }
1135 
release()1136 void ImageReceiverNapi::release()
1137 {
1138     if (!isRelease) {
1139         NativeRelease();
1140         isRelease = true;
1141     }
1142 }
1143 }  // namespace Media
1144 }  // namespace OHOS
1145