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