1 /*
2  * Copyright (C) 2021 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 "player_callback_napi.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "media_log.h"
20 #include "scope_guard.h"
21 
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "PlayerCallbackNapi"};
24 const std::string PLAY_CALLBACK_NAME = "play";
25 const std::string PAUSE_CALLBACK_NAME = "pause";
26 const std::string STOP_CALLBACK_NAME = "stop";
27 const std::string RESET_CALLBACK_NAME = "reset";
28 const std::string DATA_LOAD_CALLBACK_NAME = "dataLoad";
29 const std::string FINISH_CALLBACK_NAME = "finish";
30 const std::string TIME_UPDATE_CALLBACK_NAME = "timeUpdate";
31 const std::string ERROR_CALLBACK_NAME = "error";
32 const std::string VOL_CHANGE_CALLBACK_NAME = "volumeChange";
33 const std::string BUFFERING_UPDATE_CALLBACK_NAME = "bufferingUpdate";
34 const std::string AUDIO_INTERRUPT_CALLBACK_NAME = "audioInterrupt";
35 }
36 
37 namespace OHOS {
38 namespace Media {
PlayerCallbackNapi(napi_env env)39 PlayerCallbackNapi::PlayerCallbackNapi(napi_env env)
40     : env_(env)
41 {
42     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
43 }
44 
~PlayerCallbackNapi()45 PlayerCallbackNapi::~PlayerCallbackNapi()
46 {
47     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
48 }
49 
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)50 void PlayerCallbackNapi::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
51 {
52     std::lock_guard<std::mutex> lock(mutex_);
53     refMap_[name] = ref;
54 }
55 
ClearCallbackReference()56 void PlayerCallbackNapi::ClearCallbackReference()
57 {
58     std::lock_guard<std::mutex> lock(mutex_);
59     refMap_.clear();
60 }
61 
SendErrorCallback(MediaServiceExtErrCode errCode,const std::string & info)62 void PlayerCallbackNapi::SendErrorCallback(MediaServiceExtErrCode errCode, const std::string &info)
63 {
64     MEDIA_LOGE("in ErrorCallback: %{public}s", info.c_str());
65     std::lock_guard<std::mutex> lock(mutex_);
66     if (refMap_.find(ERROR_CALLBACK_NAME) == refMap_.end()) {
67         MEDIA_LOGW("can not find error callback!");
68         return;
69     }
70 
71     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
72     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
73 
74     cb->callback = refMap_.at(ERROR_CALLBACK_NAME);
75     cb->callbackName = ERROR_CALLBACK_NAME;
76     cb->errorMsg = info;
77     cb->errorCode = errCode;
78     return OnJsCallBackError(cb);
79 }
80 
GetCurrentState() const81 PlayerStates PlayerCallbackNapi::GetCurrentState() const
82 {
83     return currentState_;
84 }
85 
OnError(int32_t errorCode,const std::string & errorMsg)86 void PlayerCallbackNapi::OnError(int32_t errorCode, const std::string &errorMsg)
87 {
88     MEDIA_LOGE("OnErrorCb:errorCode %{public}d, errorMsg %{public}s", errorCode, errorMsg.c_str());
89     MediaServiceExtErrCode err = MSErrorToExtError(static_cast<MediaServiceErrCode>(errorCode));
90     return SendErrorCallback(err, errorMsg);
91 }
92 
OnInfo(PlayerOnInfoType type,int32_t extra,const Format & infoBody)93 void PlayerCallbackNapi::OnInfo(PlayerOnInfoType type, int32_t extra, const Format &infoBody)
94 {
95     std::lock_guard<std::mutex> lock(mutex_);
96     MEDIA_LOGI("OnInfo is called, PlayerOnInfoType: %{public}d", type);
97     switch (type) {
98         case INFO_TYPE_SEEKDONE:
99             OnSeekDoneCb(extra);
100             break;
101         case INFO_TYPE_EOS:
102             OnEosCb(extra);
103             break;
104         case INFO_TYPE_STATE_CHANGE:
105             OnStateChangeCb(static_cast<PlayerStates>(extra));
106             break;
107         case INFO_TYPE_POSITION_UPDATE:
108             OnPositionUpdateCb(extra);
109             break;
110         case INFO_TYPE_MESSAGE:
111             OnMessageCb(extra);
112             break;
113         case INFO_TYPE_VOLUME_CHANGE:
114             OnVolumeChangeCb();
115             break;
116         case INFO_TYPE_BUFFERING_UPDATE:
117             OnBufferingUpdateCb(infoBody);
118             break;
119         case INFO_TYPE_INTERRUPT_EVENT:
120             OnAudioInterruptCb(infoBody);
121             break;
122         default:
123             break;
124     }
125     MEDIA_LOGD("send OnInfo callback success");
126 }
127 
OnSeekDoneCb(int32_t currentPositon) const128 void PlayerCallbackNapi::OnSeekDoneCb(int32_t currentPositon) const
129 {
130     MEDIA_LOGD("OnSeekDone is called, currentPositon: %{public}d", currentPositon);
131 }
132 
OnBufferingUpdateCb(const Format & infoBody) const133 void PlayerCallbackNapi::OnBufferingUpdateCb(const Format &infoBody) const
134 {
135     if (refMap_.find(BUFFERING_UPDATE_CALLBACK_NAME) == refMap_.end()) {
136         MEDIA_LOGW("can not find buffering update callback!");
137         return;
138     }
139 
140     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
141     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
142     cb->callback = refMap_.at(BUFFERING_UPDATE_CALLBACK_NAME);
143     cb->callbackName = BUFFERING_UPDATE_CALLBACK_NAME;
144 
145     int32_t value = 0;
146     int32_t bufferingType = -1;
147     if (infoBody.ContainKey(std::string(PlayerKeys::PLAYER_BUFFERING_START))) {
148         bufferingType = BUFFERING_START;
149         (void)infoBody.GetIntValue(std::string(PlayerKeys::PLAYER_BUFFERING_START), value);
150     } else if (infoBody.ContainKey(std::string(PlayerKeys::PLAYER_BUFFERING_END))) {
151         bufferingType = BUFFERING_END;
152         (void)infoBody.GetIntValue(std::string(PlayerKeys::PLAYER_BUFFERING_END), value);
153     } else if (infoBody.ContainKey(std::string(PlayerKeys::PLAYER_BUFFERING_PERCENT))) {
154         bufferingType = BUFFERING_PERCENT;
155         (void)infoBody.GetIntValue(std::string(PlayerKeys::PLAYER_BUFFERING_PERCENT), value);
156     } else if (infoBody.ContainKey(std::string(PlayerKeys::PLAYER_CACHED_DURATION))) {
157         bufferingType = CACHED_DURATION;
158         (void)infoBody.GetIntValue(std::string(PlayerKeys::PLAYER_CACHED_DURATION), value);
159     } else {
160         return;
161     }
162 
163     MEDIA_LOGD("OnBufferingUpdateCb is called, buffering type: %{public}d value: %{public}d", bufferingType, value);
164 
165     cb->valueVec.push_back(bufferingType);
166     cb->valueVec.push_back(value);
167     return OnJsCallBackIntVec(cb);
168 }
169 
OnEosCb(int32_t isLooping) const170 void PlayerCallbackNapi::OnEosCb(int32_t isLooping) const
171 {
172     MEDIA_LOGD("OnEndOfStream is called, isloop: %{public}d", isLooping);
173 }
174 
OnStateChangeCb(PlayerStates state)175 void PlayerCallbackNapi::OnStateChangeCb(PlayerStates state)
176 {
177     MEDIA_LOGD("OnStateChanged is called, current state: %{public}d", state);
178     currentState_ = state;
179 
180     std::string callbackName = "unknown";
181     switch (state) {
182         case PLAYER_PREPARED:
183             callbackName = DATA_LOAD_CALLBACK_NAME;
184             break;
185         case PLAYER_STARTED:
186             callbackName = PLAY_CALLBACK_NAME;
187             break;
188         case PLAYER_PAUSED:
189             callbackName = PAUSE_CALLBACK_NAME;
190             break;
191         case PLAYER_STOPPED:
192             callbackName = STOP_CALLBACK_NAME;
193             break;
194         case PLAYER_IDLE:
195             callbackName = RESET_CALLBACK_NAME;
196             break;
197         case PLAYER_PLAYBACK_COMPLETE:
198             callbackName = FINISH_CALLBACK_NAME;
199             break;
200         default:
201             callbackName = "unknown";
202             break;
203     }
204 
205     if (refMap_.find(callbackName) == refMap_.end()) {
206         MEDIA_LOGW("can not find %{public}s callback!", callbackName.c_str());
207         return;
208     }
209 
210     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
211     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
212     cb->callback = refMap_.at(callbackName);
213     cb->callbackName = callbackName;
214     return OnJsCallBack(cb);
215 }
216 
OnPositionUpdateCb(int32_t position) const217 void PlayerCallbackNapi::OnPositionUpdateCb(int32_t position) const
218 {
219     MEDIA_LOGD("OnPositionUpdateCb is called, position: %{public}d", position);
220     if (refMap_.find(TIME_UPDATE_CALLBACK_NAME) == refMap_.end()) {
221         MEDIA_LOGW("can not find timeupdate callback!");
222         return;
223     }
224 
225     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
226     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
227     cb->callback = refMap_.at(TIME_UPDATE_CALLBACK_NAME);
228     cb->callbackName = TIME_UPDATE_CALLBACK_NAME;
229     cb->valueVec.push_back(position);
230     return OnJsCallBackInt(cb);
231 }
232 
OnMessageCb(int32_t type) const233 void PlayerCallbackNapi::OnMessageCb(int32_t type) const
234 {
235     MEDIA_LOGD("OnMessageCb is called, type: %{public}d", type);
236 }
237 
OnVolumeChangeCb()238 void PlayerCallbackNapi::OnVolumeChangeCb()
239 {
240     MEDIA_LOGD("OnVolumeChangeCb in");
241     if (refMap_.find(VOL_CHANGE_CALLBACK_NAME) == refMap_.end()) {
242         MEDIA_LOGW("can not find vol change callback!");
243         return;
244     }
245     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
246     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
247     cb->callback = refMap_.at(VOL_CHANGE_CALLBACK_NAME);
248     cb->callbackName = VOL_CHANGE_CALLBACK_NAME;
249     return OnJsCallBack(cb);
250 }
251 
OnAudioInterruptCb(const Format & infoBody) const252 void PlayerCallbackNapi::OnAudioInterruptCb(const Format &infoBody) const
253 {
254     MEDIA_LOGD("OnAudioInterruptCb in");
255     if (refMap_.find(AUDIO_INTERRUPT_CALLBACK_NAME) == refMap_.end()) {
256         MEDIA_LOGW("can not find audio interrupt callback!");
257         return;
258     }
259 
260     PlayerJsCallback *cb = new(std::nothrow) PlayerJsCallback();
261     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
262     cb->callback = refMap_.at(AUDIO_INTERRUPT_CALLBACK_NAME);
263     cb->callbackName = AUDIO_INTERRUPT_CALLBACK_NAME;
264     int32_t eventType = 0;
265     int32_t forceType = 0;
266     int32_t hintType = 0;
267     (void)infoBody.GetIntValue(PlayerKeys::AUDIO_INTERRUPT_TYPE, eventType);
268     (void)infoBody.GetIntValue(PlayerKeys::AUDIO_INTERRUPT_FORCE, forceType);
269     (void)infoBody.GetIntValue(PlayerKeys::AUDIO_INTERRUPT_HINT, hintType);
270     cb->interruptEvent.eventType = AudioStandard::InterruptType(eventType);
271     cb->interruptEvent.forceType = AudioStandard::InterruptForceType(forceType);
272     cb->interruptEvent.hintType = AudioStandard::InterruptHint(hintType);
273     return OnJsCallBackInterrupt(cb);
274 }
275 
OnJsCallBack(PlayerJsCallback * jsCb) const276 void PlayerCallbackNapi::OnJsCallBack(PlayerJsCallback *jsCb) const
277 {
278     uv_loop_s *loop = nullptr;
279     napi_get_uv_event_loop(env_, &loop);
280     if (loop == nullptr) {
281         delete jsCb;
282         return;
283     }
284 
285     uv_work_t *work = new(std::nothrow) uv_work_t;
286     if (work == nullptr) {
287         MEDIA_LOGE("No memory");
288         delete jsCb;
289         return;
290     }
291     work->data = reinterpret_cast<void *>(jsCb);
292 
293     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
294         // Js Thread
295         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
296         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
297         std::string request = event->callbackName;
298         MEDIA_LOGD("JsCallBack %{public}s, uv_queue_work start", request.c_str());
299         do {
300             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
301             std::shared_ptr<AutoRef> ref = event->callback.lock();
302             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
303 
304             napi_handle_scope scope = nullptr;
305             napi_open_handle_scope(ref->env_, &scope);
306             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
307             ON_SCOPE_EXIT(0) {
308                 napi_close_handle_scope(ref->env_, scope);
309             };
310 
311             napi_value jsCallback = nullptr;
312             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
313             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr,
314                 "%{public}s get reference value fail", request.c_str());
315 
316             // Call back function
317             napi_value result = nullptr;
318             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 0, nullptr, &result);
319             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
320         } while (0);
321         delete event;
322         delete work;
323     });
324     if (ret != 0) {
325         MEDIA_LOGE("Failed to execute libuv work queue");
326         delete jsCb;
327         delete work;
328     }
329 }
330 
OnJsCallBackError(PlayerJsCallback * jsCb) const331 void PlayerCallbackNapi::OnJsCallBackError(PlayerJsCallback *jsCb) const
332 {
333     ON_SCOPE_EXIT(0) {
334         delete jsCb;
335     };
336 
337     uv_loop_s *loop = nullptr;
338     napi_get_uv_event_loop(env_, &loop);
339     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to napi_get_uv_event_loop");
340 
341     uv_work_t *work = new(std::nothrow) uv_work_t;
342     CHECK_AND_RETURN_LOG(work != nullptr, "Fail to new uv_work_t");
343     work->data = reinterpret_cast<void *>(jsCb);
344 
345     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
346         // Js Thread
347         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
348         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
349         std::string request = event->callbackName;
350         MEDIA_LOGD("JsCallBack %{public}s, uv_queue_work start", request.c_str());
351         do {
352             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
353             std::shared_ptr<AutoRef> ref = event->callback.lock();
354             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
355 
356             napi_handle_scope scope = nullptr;
357             napi_open_handle_scope(ref->env_, &scope);
358             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
359             ON_SCOPE_EXIT(0) {
360                 napi_close_handle_scope(ref->env_, scope);
361             };
362 
363             napi_value jsCallback = nullptr;
364             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
365             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
366                 request.c_str());
367 
368             napi_value msgValStr = nullptr;
369             nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
370             CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
371 
372             napi_value args[1] = { nullptr };
373             nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
374             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
375 
376             nstatus = CommonNapi::FillErrorArgs(ref->env_, static_cast<int32_t>(event->errorCode), args[0]);
377             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "create error callback fail");
378 
379             // Call back function
380             napi_value result = nullptr;
381             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
382             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
383         } while (0);
384         delete event;
385         delete work;
386     });
387     if (ret != 0) {
388         MEDIA_LOGE("Failed to execute libuv work queue");
389         delete jsCb;
390         delete work;
391     }
392     CANCEL_SCOPE_EXIT_GUARD(0);
393 }
394 
OnJsCallBackInt(PlayerJsCallback * jsCb) const395 void PlayerCallbackNapi::OnJsCallBackInt(PlayerJsCallback *jsCb) const
396 {
397     uv_loop_s *loop = nullptr;
398     napi_get_uv_event_loop(env_, &loop);
399     if (loop == nullptr) {
400         delete jsCb;
401         return;
402     }
403 
404     uv_work_t *work = new(std::nothrow) uv_work_t;
405     if (work == nullptr) {
406         MEDIA_LOGE("No memory");
407         delete jsCb;
408         return;
409     }
410     work->data = reinterpret_cast<void *>(jsCb);
411 
412     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
413         // Js Thread
414         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
415         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
416         std::string request = event->callbackName;
417         MEDIA_LOGD("JsCallBack %{public}s, uv_queue_work start", request.c_str());
418         do {
419             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
420             std::shared_ptr<AutoRef> ref = event->callback.lock();
421             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
422 
423             napi_handle_scope scope = nullptr;
424             napi_open_handle_scope(ref->env_, &scope);
425             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
426             ON_SCOPE_EXIT(0) { napi_close_handle_scope(ref->env_, scope); };
427 
428             napi_value jsCallback = nullptr;
429             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
430             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
431                 request.c_str());
432 
433             CHECK_AND_BREAK_LOG(event->valueVec.size() == 1, "%{public}s get reference value fail", request.c_str());
434             // Call back function
435             napi_value args[1] = { nullptr };
436             nstatus = napi_create_int32(ref->env_, event->valueVec[0], &args[0]);
437             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
438                 "%{public}s fail to create callback", request.c_str());
439 
440             napi_value result = nullptr;
441             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
442             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call seekDone callback", request.c_str());
443         } while (0);
444         delete event;
445         delete work;
446     });
447     if (ret != 0) {
448         MEDIA_LOGE("Failed to execute libuv work queue");
449         delete jsCb;
450         delete work;
451     }
452 }
453 
OnJsCallBackIntVec(PlayerJsCallback * jsCb) const454 void PlayerCallbackNapi::OnJsCallBackIntVec(PlayerJsCallback *jsCb) const
455 {
456     ON_SCOPE_EXIT(0) {
457         delete jsCb;
458     };
459 
460     uv_loop_s *loop = nullptr;
461     napi_get_uv_event_loop(env_, &loop);
462     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to napi_get_uv_event_loop");
463 
464     uv_work_t *work = new(std::nothrow) uv_work_t;
465     CHECK_AND_RETURN_LOG(work != nullptr, "Fail to new uv_work_t");
466     work->data = reinterpret_cast<void *>(jsCb);
467 
468     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
469         // Js Thread
470         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
471         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
472         std::string request = event->callbackName;
473         MEDIA_LOGD("JsCallBack %{public}s, uv_queue_work start", request.c_str());
474         do {
475             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
476             std::shared_ptr<AutoRef> ref = event->callback.lock();
477             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
478 
479             napi_handle_scope scope = nullptr;
480             napi_open_handle_scope(ref->env_, &scope);
481             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
482             ON_SCOPE_EXIT(0) {
483                 napi_close_handle_scope(ref->env_, scope);
484             };
485 
486             napi_value jsCallback = nullptr;
487             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
488             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
489                 request.c_str());
490 
491             CHECK_AND_BREAK_LOG(event->valueVec.size() == 2, "%{public}s get reference value fail", request.c_str());
492             // Call back function
493             napi_value args[2] = { nullptr };
494             nstatus = napi_create_int32(ref->env_, event->valueVec[0], &args[0]);
495             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
496                 "%{public}s fail to create callback", request.c_str());
497 
498             nstatus = napi_create_int32(ref->env_, event->valueVec[1], &args[1]);
499             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[1] != nullptr,
500                 "%{public}s fail to create callback", request.c_str());
501 
502             const size_t argCount = 2;
503             napi_value result = nullptr;
504             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
505             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call callback", request.c_str());
506         } while (0);
507         delete event;
508         delete work;
509     });
510     if (ret != 0) {
511         MEDIA_LOGE("Failed to execute libuv work queue");
512         delete jsCb;
513         delete work;
514     }
515     CANCEL_SCOPE_EXIT_GUARD(0);
516 }
517 
OnJsCallBackIntArray(PlayerJsCallback * jsCb) const518 void PlayerCallbackNapi::OnJsCallBackIntArray(PlayerJsCallback *jsCb) const
519 {
520     uv_loop_s *loop = nullptr;
521     napi_get_uv_event_loop(env_, &loop);
522     if (loop == nullptr) {
523         delete jsCb;
524         return;
525     }
526 
527     uv_work_t *work = new(std::nothrow) uv_work_t;
528     if (work == nullptr) {
529         MEDIA_LOGE("No memory");
530         delete jsCb;
531         return;
532     }
533     work->data = reinterpret_cast<void *>(jsCb);
534 
535     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
536         // Js Thread
537         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
538         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
539         std::string request = event->callbackName;
540         MEDIA_LOGD("JsCallBack %{public}s, size = %{public}zu", request.c_str(), event->valueVec.size());
541 
542         do {
543             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
544             std::shared_ptr<AutoRef> ref = event->callback.lock();
545             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
546 
547             napi_handle_scope scope = nullptr;
548             napi_open_handle_scope(ref->env_, &scope);
549             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
550             ON_SCOPE_EXIT(0) {
551                 napi_close_handle_scope(ref->env_, scope);
552             };
553 
554             napi_value jsCallback = nullptr;
555             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
556             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr,
557                 "%{public}s failed call callback", request.c_str());
558 
559             napi_value array = nullptr;
560             bool ret = CommonNapi::AddArrayInt(ref->env_, array, event->valueVec);
561             CHECK_AND_BREAK_LOG(ret == true, "%{public}s failed call callback", request.c_str());
562 
563             napi_value result = nullptr;
564             napi_value args[1] = {array};
565             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
566             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call callback", request.c_str());
567         } while (0);
568         delete event;
569         delete work;
570     });
571     if (ret != 0) {
572         MEDIA_LOGE("Failed to execute libuv work queue");
573         delete jsCb;
574         delete work;
575     }
576 }
577 
OnJsCallBackInterrupt(PlayerJsCallback * jsCb) const578 void PlayerCallbackNapi::OnJsCallBackInterrupt(PlayerJsCallback *jsCb) const
579 {
580     ON_SCOPE_EXIT(0) {
581         delete jsCb;
582     };
583 
584     uv_loop_s *loop = nullptr;
585     napi_get_uv_event_loop(env_, &loop);
586     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to napi_get_uv_event_loop");
587 
588     uv_work_t *work = new(std::nothrow) uv_work_t;
589     CHECK_AND_RETURN_LOG(work != nullptr, "Fail to new uv_work_t");
590     work->data = reinterpret_cast<void *>(jsCb);
591 
592     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
593         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
594         PlayerJsCallback *event = reinterpret_cast<PlayerJsCallback *>(work->data);
595         std::string request = event->callbackName;
596         MEDIA_LOGD("JsCallBack %{public}s", request.c_str());
597 
598         do {
599             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
600             std::shared_ptr<AutoRef> ref = event->callback.lock();
601             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
602 
603             napi_handle_scope scope = nullptr;
604             napi_open_handle_scope(ref->env_, &scope);
605             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
606             ON_SCOPE_EXIT(0) {
607                 napi_close_handle_scope(ref->env_, scope);
608             };
609 
610             napi_value jsCallback = nullptr;
611             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
612             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr,
613                 "%{public}s failed call callback", request.c_str());
614 
615             napi_value args[1] = {nullptr};
616             napi_create_object(ref->env_, &args[0]);
617             CommonNapi::SetPropertyInt32(ref->env_, args[0], "eventType",
618                 static_cast<int32_t>(event->interruptEvent.eventType));
619             CommonNapi::SetPropertyInt32(ref->env_, args[0], "forceType",
620                 static_cast<int32_t>(event->interruptEvent.forceType));
621             CommonNapi::SetPropertyInt32(ref->env_, args[0], "hintType",
622                 static_cast<int32_t>(event->interruptEvent.hintType));
623 
624             napi_value result = nullptr;
625             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
626             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call callback", request.c_str());
627         } while (0);
628         delete event;
629         delete work;
630     });
631     if (ret != 0) {
632         MEDIA_LOGE("Failed to execute libuv work queue");
633         delete jsCb;
634         delete work;
635     }
636     CANCEL_SCOPE_EXIT_GUARD(0);
637 }
638 } // namespace Media
639 } // namespace OHOS
640