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