• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "avplayer_napi.h"
17 #include "avplayer_callback.h"
18 #include "media_log.h"
19 #include "media_errors.h"
20 #ifdef SUPPORT_VIDEO
21 #include "surface_utils.h"
22 #endif
23 #include "string_ex.h"
24 
25 namespace {
26     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVPlayerNapi"};
27 }
28 
29 namespace OHOS {
30 namespace Media {
31 thread_local napi_ref AVPlayerNapi::constructor_ = nullptr;
32 const std::string CLASS_NAME = "AVPlayer";
33 
AVPlayerNapi()34 AVPlayerNapi::AVPlayerNapi()
35 {
36     MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
37 }
38 
~AVPlayerNapi()39 AVPlayerNapi::~AVPlayerNapi()
40 {
41     MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
42 }
43 
Init(napi_env env,napi_value exports)44 napi_value AVPlayerNapi::Init(napi_env env, napi_value exports)
45 {
46     napi_property_descriptor staticProperty[] = {
47         DECLARE_NAPI_STATIC_FUNCTION("createAVPlayer", JsCreateAVPlayer),
48     };
49 
50     napi_property_descriptor properties[] = {
51         DECLARE_NAPI_FUNCTION("prepare", JsPrepare),
52         DECLARE_NAPI_FUNCTION("play", JsPlay),
53         DECLARE_NAPI_FUNCTION("pause", JsPause),
54         DECLARE_NAPI_FUNCTION("stop", JsStop),
55         DECLARE_NAPI_FUNCTION("reset", JsReset),
56         DECLARE_NAPI_FUNCTION("release", JsRelease),
57         DECLARE_NAPI_FUNCTION("seek", JsSeek),
58         DECLARE_NAPI_FUNCTION("on", JsSetOnCallback),
59         DECLARE_NAPI_FUNCTION("off", JsClearOnCallback),
60         DECLARE_NAPI_FUNCTION("setVolume", JsSetVolume),
61         DECLARE_NAPI_FUNCTION("setSpeed", JsSetSpeed),
62         DECLARE_NAPI_FUNCTION("setBitrate", JsSelectBitrate),
63         DECLARE_NAPI_FUNCTION("getTrackDescription", JsGetTrackDescription),
64 
65         DECLARE_NAPI_GETTER_SETTER("url", JsGetUrl, JsSetUrl),
66         DECLARE_NAPI_GETTER_SETTER("fdSrc", JsGetAVFileDescriptor, JsSetAVFileDescriptor),
67         DECLARE_NAPI_GETTER_SETTER("surfaceId", JsGetSurfaceID, JsSetSurfaceID),
68         DECLARE_NAPI_GETTER_SETTER("loop", JsGetLoop, JsSetLoop),
69         DECLARE_NAPI_GETTER_SETTER("videoScaleType", JsGetVideoScaleType, JsSetVideoScaleType),
70         DECLARE_NAPI_GETTER_SETTER("audioInterruptMode", JsGetAudioInterruptMode, JsSetAudioInterruptMode),
71 
72         DECLARE_NAPI_GETTER("state", JsGetState),
73         DECLARE_NAPI_GETTER("currentTime", JsGetCurrentTime),
74         DECLARE_NAPI_GETTER("duration", JsGetDuration),
75         DECLARE_NAPI_GETTER("width", JsGetWidth),
76         DECLARE_NAPI_GETTER("height", JsGetHeight),
77     };
78 
79     napi_value constructor = nullptr;
80     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
81         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
82     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVPlayer class");
83 
84     status = napi_create_reference(env, constructor, 1, &constructor_);
85     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
86 
87     status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
88     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
89 
90     status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
91     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
92 
93     MEDIA_LOGI("Init success");
94     return exports;
95 }
96 
Constructor(napi_env env,napi_callback_info info)97 napi_value AVPlayerNapi::Constructor(napi_env env, napi_callback_info info)
98 {
99     napi_value result = nullptr;
100     napi_get_undefined(env, &result);
101 
102     size_t argCount = 0;
103     napi_value jsThis = nullptr;
104     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
105     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
106 
107     AVPlayerNapi *jsPlayer = new(std::nothrow) AVPlayerNapi();
108     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to new AVPlayerNapi");
109 
110     jsPlayer->env_ = env;
111     jsPlayer->player_ = PlayerFactory::CreatePlayer();
112     CHECK_AND_RETURN_RET_LOG(jsPlayer->player_ != nullptr, result, "failed to CreatePlayer");
113 
114     jsPlayer->taskQue_ = std::make_unique<TaskQueue>("AVPlayerNapi");
115     (void)jsPlayer->taskQue_->Start();
116 
117     jsPlayer->playerCb_ = std::make_shared<AVPlayerCallback>(env, jsPlayer);
118     (void)jsPlayer->player_->SetPlayerCallback(jsPlayer->playerCb_);
119 
120     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsPlayer),
121         AVPlayerNapi::Destructor, nullptr, nullptr);
122     if (status != napi_ok) {
123         delete jsPlayer;
124         MEDIA_LOGE("Failed to wrap native instance");
125         return result;
126     }
127 
128     MEDIA_LOGI("Constructor success");
129     return jsThis;
130 }
131 
Destructor(napi_env env,void * nativeObject,void * finalize)132 void AVPlayerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
133 {
134     (void)finalize;
135     if (nativeObject != nullptr) {
136         AVPlayerNapi *jsPlayer = reinterpret_cast<AVPlayerNapi *>(nativeObject);
137         jsPlayer->ClearCallbackReference();
138         auto task = jsPlayer->ReleaseTask();
139         if (task != nullptr) {
140             MEDIA_LOGI("Destructor Wait Release Task Start");
141             task->GetResult(); // sync release
142             MEDIA_LOGI("Destructor Wait Release Task End");
143         }
144         jsPlayer->taskQue_->Stop();
145         delete jsPlayer;
146     }
147     MEDIA_LOGI("Destructor success");
148 }
149 
JsCreateAVPlayer(napi_env env,napi_callback_info info)150 napi_value AVPlayerNapi::JsCreateAVPlayer(napi_env env, napi_callback_info info)
151 {
152     napi_value result = nullptr;
153     napi_get_undefined(env, &result);
154     MEDIA_LOGI("JsCreateAVPlayer In");
155 
156     std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
157 
158     // get args
159     napi_value jsThis = nullptr;
160     napi_value args[1] = { nullptr };
161     size_t argCount = 1;
162     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
163     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
164 
165     asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
166     asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
167     asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
168     asyncContext->ctorFlag = true;
169 
170     napi_value resource = nullptr;
171     napi_create_string_utf8(env, "JsCreateAVPlayer", NAPI_AUTO_LENGTH, &resource);
172     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {},
173         MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncContext.get()), &asyncContext->work));
174     NAPI_CALL(env, napi_queue_async_work(env, asyncContext->work));
175     asyncContext.release();
176     MEDIA_LOGI("JsCreateAVPlayer Out");
177     return result;
178 }
179 
PrepareTask()180 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PrepareTask()
181 {
182     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
183         MEDIA_LOGI("Prepare Task In");
184         std::unique_lock<std::mutex> lock(taskMutex_);
185 
186         auto state = GetCurrentState();
187         if (state == AVPlayerState::STATE_INITIALIZED ||
188             state == AVPlayerState::STATE_STOPPED) {
189             int32_t ret = player_->PrepareAsync();
190             if (ret != MSERR_OK) {
191                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
192                 return TaskRet(errCode, "failed to prepare");
193             }
194             preparingCond_.wait(lock, [this]() {
195                 auto state = GetCurrentState();
196                 return (state == AVPlayerState::STATE_PREPARED ||
197                         state == AVPlayerState::STATE_ERROR ||
198                         state == AVPlayerState::STATE_IDLE ||
199                         state == AVPlayerState::STATE_RELEASED);
200             });
201             if (GetCurrentState() == AVPlayerState::STATE_ERROR) {
202                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
203                     "failed to prepare, avplayer enter error status, please check error callback messages!");
204             }
205         } else if (state == AVPlayerState::STATE_PREPARED) {
206             MEDIA_LOGI("current state is prepared, invalid operation");
207         } else {
208             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
209                 "current state is not stopped or initialized, unsupport prepare operation");
210         }
211 
212         MEDIA_LOGI("Prepare Task Out");
213         return TaskRet(MSERR_EXT_API9_OK, "Success");
214     });
215 
216     (void)taskQue_->EnqueueTask(task);
217     return task;
218 }
219 
JsPrepare(napi_env env,napi_callback_info info)220 napi_value AVPlayerNapi::JsPrepare(napi_env env, napi_callback_info info)
221 {
222     napi_value result = nullptr;
223     napi_get_undefined(env, &result);
224     MEDIA_LOGI("JsPrepare In");
225 
226     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
227     napi_value args[1] = { nullptr };
228     size_t argCount = 1;
229     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
230     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
231 
232     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
233     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
234     auto state = jsPlayer->GetCurrentState();
235     if (state != AVPlayerState::STATE_INITIALIZED &&
236         state != AVPlayerState::STATE_STOPPED &&
237         state != AVPlayerState::STATE_PREPARED) {
238         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
239             "current state is not stopped or initialized, unsupport prepare operation");
240     } else {
241         promiseCtx->asyncTask = jsPlayer->PrepareTask();
242     }
243 
244     napi_value resource = nullptr;
245     napi_create_string_utf8(env, "JsPrepare", NAPI_AUTO_LENGTH, &resource);
246     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
247         [](napi_env env, void *data) {
248             MEDIA_LOGI("Wait Prepare Task Start");
249             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
250             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
251             promiseCtx->CheckTaskResult();
252             MEDIA_LOGI("Wait Prepare Task End");
253         },
254         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
255     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
256     promiseCtx.release();
257     MEDIA_LOGI("JsPrepare Out");
258     return result;
259 }
260 
PlayTask()261 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PlayTask()
262 {
263     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
264         MEDIA_LOGI("Play Task In");
265         std::unique_lock<std::mutex> lock(taskMutex_);
266 
267         auto state = GetCurrentState();
268         if (state == AVPlayerState::STATE_PREPARED ||
269             state == AVPlayerState::STATE_PAUSED ||
270             state == AVPlayerState::STATE_COMPLETED) {
271             int32_t ret = player_->Play();
272             if (ret != MSERR_OK) {
273                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
274                 return TaskRet(errCode, "failed to Play");
275             }
276             stateChangeCond_.wait(lock, [this]() {
277                 auto state = GetCurrentState();
278                 return (state == AVPlayerState::STATE_PLAYING ||
279                         state == AVPlayerState::STATE_COMPLETED ||
280                         state == AVPlayerState::STATE_ERROR ||
281                         state == AVPlayerState::STATE_IDLE ||
282                         state == AVPlayerState::STATE_RELEASED);
283             });
284         } else if (state == AVPlayerState::STATE_PLAYING) {
285             MEDIA_LOGI("current state is playing, invalid operation");
286         } else {
287             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
288                 "current state is not prepared/paused/completed, unsupport play operation");
289         }
290 
291         MEDIA_LOGI("Play Task Out");
292         return TaskRet(MSERR_EXT_API9_OK, "Success");
293     });
294     (void)taskQue_->EnqueueTask(task);
295     return task;
296 }
297 
JsPlay(napi_env env,napi_callback_info info)298 napi_value AVPlayerNapi::JsPlay(napi_env env, napi_callback_info info)
299 {
300     napi_value result = nullptr;
301     napi_get_undefined(env, &result);
302     MEDIA_LOGI("JsPlay In");
303 
304     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
305     napi_value args[1] = { nullptr };
306     size_t argCount = 1;
307     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
308     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
309 
310     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
311     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
312     auto state = jsPlayer->GetCurrentState();
313     if (state != AVPlayerState::STATE_PREPARED &&
314         state != AVPlayerState::STATE_PAUSED &&
315         state != AVPlayerState::STATE_COMPLETED &&
316         state != AVPlayerState::STATE_PLAYING) {
317         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
318             "current state is not prepared/paused/completed, unsupport play operation");
319     } else {
320         promiseCtx->asyncTask = jsPlayer->PlayTask();
321     }
322 
323     napi_value resource = nullptr;
324     napi_create_string_utf8(env, "JsPlay", NAPI_AUTO_LENGTH, &resource);
325     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
326         [](napi_env env, void *data) {
327             MEDIA_LOGI("Wait JsPlay Task Start");
328             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
329             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
330             promiseCtx->CheckTaskResult();
331             MEDIA_LOGI("Wait JsPlay Task End");
332         },
333         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
334     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
335     promiseCtx.release();
336     MEDIA_LOGI("JsPlay Out");
337     return result;
338 }
339 
PauseTask()340 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PauseTask()
341 {
342     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
343         MEDIA_LOGI("Pause Task In");
344         std::unique_lock<std::mutex> lock(taskMutex_);
345 
346         auto state = GetCurrentState();
347         if (state == AVPlayerState::STATE_PLAYING) {
348             int32_t ret = player_->Pause();
349             if (ret != MSERR_OK) {
350                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
351                 return TaskRet(errCode, "failed to Pause");
352             }
353             stateChangeCond_.wait(lock, [this]() {
354                 auto state = GetCurrentState();
355                 return (state == AVPlayerState::STATE_PAUSED ||
356                         state == AVPlayerState::STATE_COMPLETED ||
357                         state == AVPlayerState::STATE_ERROR ||
358                         state == AVPlayerState::STATE_IDLE ||
359                         state == AVPlayerState::STATE_RELEASED);
360             });
361         } else if (state == AVPlayerState::STATE_PAUSED) {
362             MEDIA_LOGI("current state is paused, invalid operation");
363         } else {
364             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
365                 "current state is not playing, unsupport pause operation");
366         }
367 
368         MEDIA_LOGI("Pause Task Out");
369         return TaskRet(MSERR_EXT_API9_OK, "Success");
370     });
371     (void)taskQue_->EnqueueTask(task);
372     return task;
373 }
374 
JsPause(napi_env env,napi_callback_info info)375 napi_value AVPlayerNapi::JsPause(napi_env env, napi_callback_info info)
376 {
377     napi_value result = nullptr;
378     napi_get_undefined(env, &result);
379     MEDIA_LOGI("JsPause In");
380 
381     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
382     napi_value args[1] = { nullptr };
383     size_t argCount = 1;
384     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
385     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
386 
387     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
388     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
389     auto state = jsPlayer->GetCurrentState();
390     if (state != AVPlayerState::STATE_PLAYING &&
391         state != AVPlayerState::STATE_PAUSED) {
392         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
393             "current state is not playing, unsupport pause operation");
394     } else {
395         promiseCtx->asyncTask = jsPlayer->PauseTask();
396     }
397 
398     napi_value resource = nullptr;
399     napi_create_string_utf8(env, "JsPause", NAPI_AUTO_LENGTH, &resource);
400     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
401         [](napi_env env, void *data) {
402             MEDIA_LOGI("Wait JsPause Task Start");
403             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
404             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
405             promiseCtx->CheckTaskResult();
406             MEDIA_LOGI("Wait JsPause Task End");
407         },
408         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
409     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
410     promiseCtx.release();
411     MEDIA_LOGI("JsPause Out");
412     return result;
413 }
414 
StopTask()415 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::StopTask()
416 {
417     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
418         MEDIA_LOGI("Stop Task In");
419         std::unique_lock<std::mutex> lock(taskMutex_);
420 
421         if (IsControllable()) {
422             int32_t ret = player_->Stop();
423             if (ret != MSERR_OK) {
424                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
425                 return TaskRet(errCode, "failed to Stop");
426             }
427             stateChangeCond_.wait(lock, [this]() {
428                 auto state = GetCurrentState();
429                 return (state == AVPlayerState::STATE_STOPPED ||
430                         state == AVPlayerState::STATE_ERROR ||
431                         state == AVPlayerState::STATE_IDLE ||
432                         state == AVPlayerState::STATE_RELEASED);
433             });
434         } else if (GetCurrentState() == AVPlayerState::STATE_STOPPED) {
435             MEDIA_LOGI("current state is stopped, invalid operation");
436         }  else {
437             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
438                 "current state is not prepared/playing/paused/completed, unsupport stop operation");
439         }
440 
441         MEDIA_LOGI("Stop Task Out");
442         return TaskRet(MSERR_EXT_API9_OK, "Success");
443     });
444     (void)taskQue_->EnqueueTask(task);
445     return task;
446 }
447 
JsStop(napi_env env,napi_callback_info info)448 napi_value AVPlayerNapi::JsStop(napi_env env, napi_callback_info info)
449 {
450     napi_value result = nullptr;
451     napi_get_undefined(env, &result);
452     MEDIA_LOGI("JsStop In");
453 
454     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
455     napi_value args[1] = { nullptr };
456     size_t argCount = 1;
457     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
458     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
459 
460     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
461     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
462     auto state = jsPlayer->GetCurrentState();
463     if (state == AVPlayerState::STATE_IDLE ||
464         state == AVPlayerState::STATE_INITIALIZED ||
465         state == AVPlayerState::STATE_RELEASED ||
466         state == AVPlayerState::STATE_ERROR) {
467         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
468             "current state is not prepared/playing/paused/completed, unsupport stop operation");
469     } else {
470         promiseCtx->asyncTask = jsPlayer->StopTask();
471     }
472 
473     napi_value resource = nullptr;
474     napi_create_string_utf8(env, "JsStop", NAPI_AUTO_LENGTH, &resource);
475     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
476         [](napi_env env, void *data) {
477             MEDIA_LOGI("Wait JsStop Task Start");
478             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
479             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
480             promiseCtx->CheckTaskResult();
481             MEDIA_LOGI("Wait JsStop Task End");
482         },
483         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
484     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
485     promiseCtx.release();
486     MEDIA_LOGI("JsStop Out");
487     return result;
488 }
489 
ResetTask()490 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ResetTask()
491 {
492     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
493         MEDIA_LOGI("Reset Task In");
494         PauseListenCurrentResource(); // Pause event listening for the current resource
495         ResetUserParameters();
496         {
497             std::unique_lock<std::mutex> lock(taskMutex_);
498             if (GetCurrentState() == AVPlayerState::STATE_RELEASED) {
499                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
500                     "current state is not playing, unsupport pause operation");
501             } else if (GetCurrentState() == AVPlayerState::STATE_IDLE) {
502                 MEDIA_LOGI("current state is idle, invalid operation");
503             } else {
504                 int32_t ret = player_->Reset();
505                 if (ret != MSERR_OK) {
506                     auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
507                     return TaskRet(errCode, "failed to Reset");
508                 }
509                 resettingCond_.wait(lock, [this]() {
510                     auto state = GetCurrentState();
511                     return state == AVPlayerState::STATE_IDLE || state == AVPlayerState::STATE_RELEASED;
512                 });
513             }
514         }
515         MEDIA_LOGI("Reset Task Out");
516         return TaskRet(MSERR_EXT_API9_OK, "Success");
517     });
518 
519     {
520         std::unique_lock<std::mutex> lock(taskMutex_);
521         (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
522         preparingCond_.notify_all(); // stop prepare
523         stateChangeCond_.notify_all(); // stop play/pause/stop
524     }
525     return task;
526 }
527 
JsReset(napi_env env,napi_callback_info info)528 napi_value AVPlayerNapi::JsReset(napi_env env, napi_callback_info info)
529 {
530     napi_value result = nullptr;
531     napi_get_undefined(env, &result);
532     MEDIA_LOGI("JsReset In");
533 
534     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
535     napi_value args[1] = { nullptr };
536     size_t argCount = 1;
537     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
538     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
539     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
540     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
541     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
542         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
543             "current state is released, unsupport reset operation");
544     } else {
545         promiseCtx->asyncTask = jsPlayer->ResetTask();
546     }
547 
548     napi_value resource = nullptr;
549     napi_create_string_utf8(env, "JsReset", NAPI_AUTO_LENGTH, &resource);
550     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
551         [](napi_env env, void *data) {
552             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
553             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
554             if (promiseCtx->asyncTask != nullptr) {
555                 MEDIA_LOGI("Wait Reset Task Start");
556                 promiseCtx->CheckTaskResult();
557                 MEDIA_LOGI("Wait Reset Task Stop");
558             }
559         },
560         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
561     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
562     promiseCtx.release();
563     MEDIA_LOGI("JsReset Out");
564     return result;
565 }
566 
ReleaseTask()567 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ReleaseTask()
568 {
569     std::shared_ptr<TaskHandler<TaskRet>> task = nullptr;
570     if (!isReleased_.load()) {
571         task = std::make_shared<TaskHandler<TaskRet>>([this]() {
572             MEDIA_LOGI("Release Task In");
573             PauseListenCurrentResource(); // Pause event listening for the current resource
574             ResetUserParameters();
575 
576             if (player_ != nullptr) {
577                 (void)player_->ReleaseSync();
578                 player_ = nullptr;
579             }
580 
581             if (playerCb_ != nullptr) {
582                 playerCb_->Release();
583             }
584             MEDIA_LOGI("Release Task Out");
585             return TaskRet(MSERR_EXT_API9_OK, "Success");
586         });
587 
588         std::unique_lock<std::mutex> lock(taskMutex_);
589         isReleased_.store(true);
590         (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
591         preparingCond_.notify_all(); // stop wait prepare
592         resettingCond_.notify_all(); // stop wait reset
593         stateChangeCond_.notify_all(); // stop wait play/pause/stop
594     }
595     return task;
596 }
597 
JsRelease(napi_env env,napi_callback_info info)598 napi_value AVPlayerNapi::JsRelease(napi_env env, napi_callback_info info)
599 {
600     napi_value result = nullptr;
601     napi_get_undefined(env, &result);
602     MEDIA_LOGI("JsRelease In");
603 
604     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
605     napi_value args[1] = { nullptr };
606     size_t argCount = 1;
607     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
608     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
609     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
610     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
611     promiseCtx->asyncTask = jsPlayer->ReleaseTask();
612 
613     napi_value resource = nullptr;
614     napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
615     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
616         [](napi_env env, void *data) {
617             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
618             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
619             if (promiseCtx->asyncTask != nullptr) {
620                 MEDIA_LOGI("Wait Release Task Start");
621                 promiseCtx->CheckTaskResult();
622                 MEDIA_LOGI("Wait Release Task Stop");
623             }
624         },
625         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
626     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
627     promiseCtx.release();
628     MEDIA_LOGI("JsRelease Out");
629     return result;
630 }
631 
JsSeek(napi_env env,napi_callback_info info)632 napi_value AVPlayerNapi::JsSeek(napi_env env, napi_callback_info info)
633 {
634     napi_value result = nullptr;
635     napi_get_undefined(env, &result);
636     MEDIA_LOGI("JsSeek In");
637 
638     napi_value args[2] = { nullptr }; // args[0]:timeMs, args[1]:SeekMode
639     size_t argCount = 2; // args[0]:timeMs, args[1]:SeekMode
640     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
641     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
642 
643     napi_valuetype valueType = napi_undefined;
644     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
645         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek time is not number");
646         return result;
647     }
648 
649     int32_t time = -1;
650     napi_status status = napi_get_value_int32(env, args[0], &time);
651     if (status != napi_ok || time < 0) {
652         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
653             "invalid parameters, please check the input seek time");
654         return result;
655     }
656 
657     int32_t mode = SEEK_PREVIOUS_SYNC;
658     if (args[1] != nullptr) {
659         if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
660             jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek mode is not number");
661             return result;
662         }
663         status = napi_get_value_int32(env, args[1], &mode);
664         if (status != napi_ok || mode < SEEK_NEXT_SYNC || mode > SEEK_CLOSEST) {
665             jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
666                 "invalid parameters, please check the input seek mode");
667             return result;
668         }
669     }
670 
671     if (!jsPlayer->IsControllable()) {
672         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
673             "current state is not prepared/playing/paused/completed, unsupport seek operation");
674         return result;
675     }
676 
677     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, time, mode]() {
678         MEDIA_LOGI("Seek Task");
679         if (jsPlayer->player_ != nullptr) {
680             (void)jsPlayer->player_->Seek(time, static_cast<PlayerSeekMode>(mode));
681         }
682     });
683     (void)jsPlayer->taskQue_->EnqueueTask(task);
684     return result;
685 }
686 
JsSetSpeed(napi_env env,napi_callback_info info)687 napi_value AVPlayerNapi::JsSetSpeed(napi_env env, napi_callback_info info)
688 {
689     napi_value result = nullptr;
690     napi_get_undefined(env, &result);
691     MEDIA_LOGI("JsSetSpeed In");
692 
693     napi_value args[1] = { nullptr };
694     size_t argCount = 1; // setSpeed(speed: number)
695     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
696     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
697 
698     napi_valuetype valueType = napi_undefined;
699     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
700         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "speed mode is not number");
701         return result;
702     }
703 
704     int32_t mode = SPEED_FORWARD_1_00_X;
705     napi_status status = napi_get_value_int32(env, args[0], &mode);
706     if (status != napi_ok || mode < SPEED_FORWARD_0_75_X || mode > SPEED_FORWARD_2_00_X) {
707         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
708             "invalid parameters, please check the speed mode");
709         return result;
710     }
711 
712     if (!jsPlayer->IsControllable()) {
713         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
714             "current state is not prepared/playing/paused/completed, unsupport speed operation");
715         return result;
716     }
717 
718     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, mode]() {
719         MEDIA_LOGI("Speed Task");
720         if (jsPlayer->player_ != nullptr) {
721             (void)jsPlayer->player_->SetPlaybackSpeed(static_cast<PlaybackRateMode>(mode));
722         }
723     });
724     (void)jsPlayer->taskQue_->EnqueueTask(task);
725     MEDIA_LOGI("JsSetSpeed Out");
726     return result;
727 }
728 
JsSetVolume(napi_env env,napi_callback_info info)729 napi_value AVPlayerNapi::JsSetVolume(napi_env env, napi_callback_info info)
730 {
731     napi_value result = nullptr;
732     napi_get_undefined(env, &result);
733     MEDIA_LOGI("JsSetVolume In");
734 
735     napi_value args[1] = { nullptr };
736     size_t argCount = 1; // setVolume(vol: number)
737     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
738     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
739 
740     napi_valuetype valueType = napi_undefined;
741     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
742         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "setVolume level is not number");
743         return result;
744     }
745 
746     double volumeLevel = 1.0f;
747     napi_status status = napi_get_value_double(env, args[0], &volumeLevel);
748     if (status != napi_ok || volumeLevel < 0.0f || volumeLevel > 1.0f) {
749         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, check volume level");
750         return result;
751     }
752 
753     if (!jsPlayer->IsControllable()) {
754         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
755             "current state is not prepared/playing/paused/completed, unsupport volume operation");
756         return result;
757     }
758 
759     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, volumeLevel]() {
760         MEDIA_LOGI("SetVolume Task");
761         if (jsPlayer->player_ != nullptr) {
762             (void)jsPlayer->player_->SetVolume(volumeLevel, volumeLevel);
763         }
764     });
765     (void)jsPlayer->taskQue_->EnqueueTask(task);
766     MEDIA_LOGI("JsSetVolume Out");
767     return result;
768 }
769 
JsSelectBitrate(napi_env env,napi_callback_info info)770 napi_value AVPlayerNapi::JsSelectBitrate(napi_env env, napi_callback_info info)
771 {
772     napi_value result = nullptr;
773     napi_get_undefined(env, &result);
774     MEDIA_LOGI("JsSelectBitrate In");
775 
776     napi_value args[1] = { nullptr };
777     size_t argCount = 1; // selectBitrate(bitRate: number)
778     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
779     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
780 
781     napi_valuetype valueType = napi_undefined;
782     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
783         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "selectBitrate is not number");
784         return result;
785     }
786 
787     int32_t bitrate = 0;
788     napi_status status = napi_get_value_int32(env, args[0], &bitrate);
789     if (status != napi_ok || bitrate < 0) {
790         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input bitrate");
791         return result;
792     }
793 
794     if (!jsPlayer->IsControllable()) {
795         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
796             "current state is not prepared/playing/paused/completed, unsupport select bitrate operation");
797         return result;
798     }
799 
800     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, bitrate]() {
801         MEDIA_LOGI("SelectBitRate Task");
802         if (jsPlayer->player_ != nullptr) {
803             (void)jsPlayer->player_->SelectBitRate(static_cast<uint32_t>(bitrate));
804         }
805     });
806     (void)jsPlayer->taskQue_->EnqueueTask(task);
807     return result;
808 }
809 
SetSource(std::string url)810 void AVPlayerNapi::SetSource(std::string url)
811 {
812     MEDIA_LOGI("input url is %{public}s!", url.c_str());
813     bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
814     bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
815     if (isNetwork) {
816         auto task = std::make_shared<TaskHandler<void>>([this, url]() {
817             MEDIA_LOGI("SetNetworkSource Task");
818             if (player_ != nullptr) {
819                 if (player_->SetSource(url) != MSERR_OK) {
820                     OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to SetSourceNetWork");
821                 }
822             }
823         });
824         (void)taskQue_->EnqueueTask(task);
825         task->GetResult();
826     } else if (isFd) {
827         const std::string fdHead = "fd://";
828         std::string inputFd = url.substr(fdHead.size());
829         int32_t fd = -1;
830         if (!StrToInt(inputFd, fd) || fd < 0) {
831             OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
832                 "invalid parameters, The input parameter is not a fd://+numeric string");
833             return;
834         }
835 
836         auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
837             MEDIA_LOGI("SetFdSource Task");
838             if (player_ != nullptr) {
839                 if (player_->SetSource(fd, 0, -1) != MSERR_OK) {
840                     OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to SetSourceFd");
841                 }
842             }
843         });
844         (void)taskQue_->EnqueueTask(task);
845         task->GetResult();
846     } else {
847         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
848             "invalid parameters, The input parameter is not fd:// or network address");
849     }
850 }
851 
JsSetUrl(napi_env env,napi_callback_info info)852 napi_value AVPlayerNapi::JsSetUrl(napi_env env, napi_callback_info info)
853 {
854     napi_value result = nullptr;
855     napi_get_undefined(env, &result);
856     MEDIA_LOGI("JsSetUrl In");
857 
858     napi_value args[1] = { nullptr };
859     size_t argCount = 1; // url: string
860     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
861     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
862 
863     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
864         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
865         return result;
866     }
867 
868     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
869     napi_valuetype valueType = napi_undefined;
870     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
871         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
872         return result;
873     }
874 
875     // get url from js
876     jsPlayer->url_ = CommonNapi::GetStringArgument(env, args[0]);
877     jsPlayer->SetSource(jsPlayer->url_);
878 
879     MEDIA_LOGI("JsSetUrl Out");
880     return result;
881 }
882 
JsGetUrl(napi_env env,napi_callback_info info)883 napi_value AVPlayerNapi::JsGetUrl(napi_env env, napi_callback_info info)
884 {
885     napi_value result = nullptr;
886     napi_get_undefined(env, &result);
887     MEDIA_LOGI("JsGetUrl In");
888 
889     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
890     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
891 
892     napi_value value = nullptr;
893     (void)napi_create_string_utf8(env, jsPlayer->url_.c_str(), NAPI_AUTO_LENGTH, &value);
894 
895     MEDIA_LOGI("JsGetUrl Out Current Url: %{public}s", jsPlayer->url_.c_str());
896     return value;
897 }
898 
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)899 napi_value AVPlayerNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
900 {
901     napi_value result = nullptr;
902     napi_get_undefined(env, &result);
903     MEDIA_LOGI("JsSetAVFileDescriptor In");
904 
905     napi_value args[1] = { nullptr };
906     size_t argCount = 1; // url: string
907     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
908     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
909 
910     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
911         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set fd");
912         return result;
913     }
914 
915     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
916     napi_valuetype valueType = napi_undefined;
917     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
918         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAVFileDescriptor is not napi_object");
919         return result;
920     }
921 
922     if (!CommonNapi::GetFdArgument(env, args[0], jsPlayer->fileDescriptor_)) {
923         MEDIA_LOGE("get fileDescriptor argument failed!");
924         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
925             "invalid parameters, please check the input parameters(fileDescriptor)");
926         return result;
927     }
928 
929     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
930         MEDIA_LOGI("SetAVFileDescriptor Task");
931         if (jsPlayer->player_ != nullptr) {
932             auto playerFd = jsPlayer->fileDescriptor_;
933             if (jsPlayer->player_->SetSource(playerFd.fd, playerFd.offset, playerFd.length) != MSERR_OK) {
934                 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource FileDescriptor failed");
935             }
936         }
937     });
938     (void)jsPlayer->taskQue_->EnqueueTask(task);
939     task->GetResult();
940 
941     MEDIA_LOGI("JsSetAVFileDescriptor Out");
942     return result;
943 }
944 
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)945 napi_value AVPlayerNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
946 {
947     napi_value result = nullptr;
948     napi_get_undefined(env, &result);
949     MEDIA_LOGI("JsGetAVFileDescriptor In");
950 
951     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
952     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
953 
954     napi_value value = nullptr;
955     (void)napi_create_object(env, &value);
956     (void)CommonNapi::AddNumberPropInt32(env, value, "fd", jsPlayer->fileDescriptor_.fd);
957     (void)CommonNapi::AddNumberPropInt64(env, value, "offset", jsPlayer->fileDescriptor_.offset);
958     (void)CommonNapi::AddNumberPropInt64(env, value, "length", jsPlayer->fileDescriptor_.length);
959 
960     MEDIA_LOGI("JsGetAVFileDescriptor Out");
961     return value;
962 }
963 
964 #ifdef SUPPORT_VIDEO
SetSurface(const std::string & surfaceStr)965 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
966 {
967     MEDIA_LOGI("get surface, surfaceStr = %{public}s", surfaceStr.c_str());
968     uint64_t surfaceId = 0;
969     if (surfaceStr.empty() || surfaceStr[0] < '0' || surfaceStr[0] > '9') {
970         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
971             "Please obtain the surface from XComponentController.getXComponentSurfaceId");
972         return;
973     }
974     surfaceId = std::stoull(surfaceStr);
975     MEDIA_LOGI("get surface, surfaceId = (%{public}" PRIu64 ")", surfaceId);
976 
977     auto surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
978     if (surface == nullptr) {
979         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SurfaceUtils cannot convert ID to Surface");
980         return;
981     }
982 
983     auto task = std::make_shared<TaskHandler<void>>([this, surface]() {
984         MEDIA_LOGI("SetSurface Task");
985         if (player_ != nullptr) {
986             (void)player_->SetVideoSurface(surface);
987         }
988     });
989     (void)taskQue_->EnqueueTask(task);
990     task->GetResult();
991 }
992 #else
SetSurface(const std::string & surfaceStr)993 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
994 {
995     (void)surfaceStr;
996     OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The music player does not need to support (Surface)");
997 }
998 #endif
999 
JsSetSurfaceID(napi_env env,napi_callback_info info)1000 napi_value AVPlayerNapi::JsSetSurfaceID(napi_env env, napi_callback_info info)
1001 {
1002     napi_value result = nullptr;
1003     napi_get_undefined(env, &result);
1004     MEDIA_LOGI("JsSetSurfaceID In");
1005 
1006     napi_value args[1] = { nullptr };
1007     size_t argCount = 1; // surfaceId?: string
1008     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1009     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1010 
1011     napi_valuetype valueType = napi_undefined;
1012     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1013         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "the attribute(SurfaceID) input is not string");
1014         return result;
1015     }
1016 
1017     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_INITIALIZED) {
1018         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1019             "the attribute(SurfaceID) can only be set in the initialized state");
1020         return result;
1021     }
1022 
1023     // get url from js
1024     jsPlayer->surface_ = CommonNapi::GetStringArgument(env, args[0]);
1025     jsPlayer->SetSurface(jsPlayer->surface_);
1026     MEDIA_LOGI("JsSetSurfaceID Out");
1027     return result;
1028 }
1029 
JsGetSurfaceID(napi_env env,napi_callback_info info)1030 napi_value AVPlayerNapi::JsGetSurfaceID(napi_env env, napi_callback_info info)
1031 {
1032     napi_value result = nullptr;
1033     napi_get_undefined(env, &result);
1034     MEDIA_LOGI("JsGetSurfaceID In");
1035 
1036     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1037     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1038 
1039     napi_value value = nullptr;
1040     (void)napi_create_string_utf8(env, jsPlayer->surface_.c_str(), NAPI_AUTO_LENGTH, &value);
1041 
1042     MEDIA_LOGI("JsGetSurfaceID Out Current SurfaceID: %{public}s", jsPlayer->surface_.c_str());
1043     return value;
1044 }
1045 
JsSetLoop(napi_env env,napi_callback_info info)1046 napi_value AVPlayerNapi::JsSetLoop(napi_env env, napi_callback_info info)
1047 {
1048     napi_value result = nullptr;
1049     napi_get_undefined(env, &result);
1050     MEDIA_LOGI("JsSetLoop In");
1051 
1052     napi_value args[1] = { nullptr };
1053     size_t argCount = 1; // loop: boolenan
1054     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1055     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1056 
1057     if (!jsPlayer->IsControllable()) {
1058         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1059             "current state is not prepared/playing/paused/completed, unsupport loop operation");
1060         return result;
1061     }
1062 
1063     napi_valuetype valueType = napi_undefined;
1064     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
1065         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetLoop is not napi_boolean");
1066         return result;
1067     }
1068 
1069     napi_status status = napi_get_value_bool(env, args[0], &jsPlayer->loop_);
1070     if (status != napi_ok) {
1071         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1072             "invalid parameters, please check the input loop");
1073         return result;
1074     }
1075 
1076     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1077         MEDIA_LOGI("SetLooping Task");
1078         if (jsPlayer->player_ != nullptr) {
1079             (void)jsPlayer->player_->SetLooping(jsPlayer->loop_);
1080         }
1081     });
1082     (void)jsPlayer->taskQue_->EnqueueTask(task);
1083     MEDIA_LOGI("JsSetLoop Out");
1084     return result;
1085 }
1086 
JsGetLoop(napi_env env,napi_callback_info info)1087 napi_value AVPlayerNapi::JsGetLoop(napi_env env, napi_callback_info info)
1088 {
1089     napi_value result = nullptr;
1090     napi_get_undefined(env, &result);
1091     MEDIA_LOGI("JsGetLoop In");
1092 
1093     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1094     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1095 
1096     napi_value value = nullptr;
1097     (void)napi_get_boolean(env, jsPlayer->loop_, &value);
1098     MEDIA_LOGI("JsGetLoop Out Current Loop: %{public}d", jsPlayer->loop_);
1099     return value;
1100 }
1101 
JsSetVideoScaleType(napi_env env,napi_callback_info info)1102 napi_value AVPlayerNapi::JsSetVideoScaleType(napi_env env, napi_callback_info info)
1103 {
1104     napi_value result = nullptr;
1105     napi_get_undefined(env, &result);
1106     MEDIA_LOGI("JsSetVideoScaleType In");
1107 
1108     napi_value args[1] = { nullptr };
1109     size_t argCount = 1;
1110     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1111     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1112 
1113     if (!jsPlayer->IsControllable()) {
1114         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1115             "current state is not prepared/playing/paused/completed, unsupport video scale operation");
1116         return result;
1117     }
1118 
1119     napi_valuetype valueType = napi_undefined;
1120     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1121         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetVideoScaleType is not napi_number");
1122         return result;
1123     }
1124 
1125     int32_t videoScaleType = 0;
1126     napi_status status = napi_get_value_int32(env, args[0], &videoScaleType);
1127     if (status != napi_ok || videoScaleType < VIDEO_SCALE_TYPE_FIT || videoScaleType > VIDEO_SCALE_TYPE_FIT_CROP) {
1128         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input scale type");
1129         return result;
1130     }
1131     jsPlayer->videoScaleType_ = videoScaleType;
1132 
1133     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, videoScaleType]() {
1134         MEDIA_LOGI("SetVideoScaleType Task");
1135         if (jsPlayer->player_ != nullptr) {
1136             Format format;
1137             (void)format.PutIntValue(PlayerKeys::VIDEO_SCALE_TYPE, videoScaleType);
1138             (void)jsPlayer->player_->SetParameter(format);
1139         }
1140     });
1141     (void)jsPlayer->taskQue_->EnqueueTask(task);
1142     MEDIA_LOGI("JsSetVideoScaleType Out");
1143     return result;
1144 }
1145 
JsGetVideoScaleType(napi_env env,napi_callback_info info)1146 napi_value AVPlayerNapi::JsGetVideoScaleType(napi_env env, napi_callback_info info)
1147 {
1148     napi_value result = nullptr;
1149     napi_get_undefined(env, &result);
1150     MEDIA_LOGI("JsGetVideoScaleType In");
1151 
1152     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1153     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1154 
1155     napi_value value = nullptr;
1156     (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->videoScaleType_), &value);
1157     MEDIA_LOGI("JsGetVideoScaleType Out Current VideoScale: %{public}d", jsPlayer->videoScaleType_);
1158     return value;
1159 }
1160 
JsSetAudioInterruptMode(napi_env env,napi_callback_info info)1161 napi_value AVPlayerNapi::JsSetAudioInterruptMode(napi_env env, napi_callback_info info)
1162 {
1163     napi_value result = nullptr;
1164     napi_get_undefined(env, &result);
1165     MEDIA_LOGI("JsSetAudioInterruptMode In");
1166 
1167     napi_value args[1] = { nullptr };
1168     size_t argCount = 1;
1169     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1170     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1171 
1172     if (!jsPlayer->IsControllable()) {
1173         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1174             "current state is not prepared/playing/paused/completed, unsupport audio interrupt operation");
1175         return result;
1176     }
1177 
1178     napi_valuetype valueType = napi_undefined;
1179     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1180         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAudioInterruptMode is not napi_number");
1181         return result;
1182     }
1183 
1184     int32_t interruptMode = 0;
1185     napi_status status = napi_get_value_int32(env, args[0], &interruptMode);
1186     if (status != napi_ok ||
1187         interruptMode < AudioStandard::InterruptMode::SHARE_MODE ||
1188         interruptMode > AudioStandard::InterruptMode::INDEPENDENT_MODE) {
1189         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1190             "invalid parameters, please check the input interrupt Mode");
1191         return result;
1192     }
1193     jsPlayer->interruptMode_ = static_cast<AudioStandard::InterruptMode>(interruptMode);
1194 
1195     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1196         MEDIA_LOGI("SetAudioInterruptMode Task");
1197         if (jsPlayer->player_ != nullptr) {
1198             Format format;
1199             (void)format.PutIntValue(PlayerKeys::AUDIO_INTERRUPT_MODE, jsPlayer->interruptMode_);
1200             (void)jsPlayer->player_->SetParameter(format);
1201         }
1202     });
1203     (void)jsPlayer->taskQue_->EnqueueTask(task);
1204     MEDIA_LOGI("JsSetAudioInterruptMode Out");
1205     return result;
1206 }
1207 
JsGetAudioInterruptMode(napi_env env,napi_callback_info info)1208 napi_value AVPlayerNapi::JsGetAudioInterruptMode(napi_env env, napi_callback_info info)
1209 {
1210     napi_value result = nullptr;
1211     napi_get_undefined(env, &result);
1212     MEDIA_LOGI("JsGetAudioInterruptMode In");
1213 
1214     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1215     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1216 
1217     napi_value value = nullptr;
1218     (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->interruptMode_), &value);
1219     MEDIA_LOGI("JsGetAudioInterruptMode Out");
1220     return value;
1221 }
1222 
JsGetCurrentTime(napi_env env,napi_callback_info info)1223 napi_value AVPlayerNapi::JsGetCurrentTime(napi_env env, napi_callback_info info)
1224 {
1225     napi_value result = nullptr;
1226     napi_get_undefined(env, &result);
1227     MEDIA_LOGI("JsGetCurrentTime In");
1228 
1229     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1230     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1231 
1232     int32_t currentTime = -1;
1233     if (jsPlayer->IsControllable()) {
1234         currentTime = jsPlayer->position_;
1235     }
1236 
1237     napi_value value = nullptr;
1238     (void)napi_create_int32(env, currentTime, &value);
1239     std::string curState = jsPlayer->GetCurrentState();
1240     MEDIA_LOGI("JsGetCurrenTime Out, state %{public}s, time: %{public}d", curState.c_str(), currentTime);
1241     return value;
1242 }
1243 
JsGetDuration(napi_env env,napi_callback_info info)1244 napi_value AVPlayerNapi::JsGetDuration(napi_env env, napi_callback_info info)
1245 {
1246     napi_value result = nullptr;
1247     napi_get_undefined(env, &result);
1248     MEDIA_LOGI("JsGetDuration In");
1249 
1250     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1251     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1252 
1253     int32_t duration = -1;
1254     if (jsPlayer->IsControllable()) {
1255         duration = jsPlayer->duration_;
1256     }
1257 
1258     napi_value value = nullptr;
1259     (void)napi_create_int32(env, duration, &value);
1260     std::string curState = jsPlayer->GetCurrentState();
1261     MEDIA_LOGI("JsGetDuration Out, state %{public}s, duration %{public}d", curState.c_str(), duration);
1262     return value;
1263 }
1264 
IsControllable()1265 bool AVPlayerNapi::IsControllable()
1266 {
1267     auto state = GetCurrentState();
1268     if (state == AVPlayerState::STATE_PREPARED || state == AVPlayerState::STATE_PLAYING ||
1269         state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_COMPLETED) {
1270         return true;
1271     } else {
1272         return false;
1273     }
1274 }
1275 
GetCurrentState()1276 std::string AVPlayerNapi::GetCurrentState()
1277 {
1278     if (isReleased_.load()) {
1279         return AVPlayerState::STATE_RELEASED;
1280     } else {
1281         std::string curState = AVPlayerState::STATE_ERROR;
1282         static const std::map<PlayerStates, std::string> stateMap = {
1283             {PLAYER_IDLE, AVPlayerState::STATE_IDLE},
1284             {PLAYER_INITIALIZED, AVPlayerState::STATE_INITIALIZED},
1285             {PLAYER_PREPARED, AVPlayerState::STATE_PREPARED},
1286             {PLAYER_STARTED, AVPlayerState::STATE_PLAYING},
1287             {PLAYER_PAUSED, AVPlayerState::STATE_PAUSED},
1288             {PLAYER_STOPPED, AVPlayerState::STATE_STOPPED},
1289             {PLAYER_PLAYBACK_COMPLETE, AVPlayerState::STATE_COMPLETED},
1290             {PLAYER_STATE_ERROR, AVPlayerState::STATE_ERROR},
1291         };
1292 
1293         if (stateMap.find(state_) != stateMap.end()) {
1294             curState = stateMap.at(state_);
1295         }
1296         return curState;
1297     }
1298 }
1299 
JsGetState(napi_env env,napi_callback_info info)1300 napi_value AVPlayerNapi::JsGetState(napi_env env, napi_callback_info info)
1301 {
1302     napi_value result = nullptr;
1303     napi_get_undefined(env, &result);
1304     MEDIA_LOGI("JsGetState In");
1305 
1306     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1307     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1308 
1309     std::string curState = jsPlayer->GetCurrentState();
1310     napi_value value = nullptr;
1311     (void)napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &value);
1312     MEDIA_LOGI("JsGetState Out");
1313     return value;
1314 }
1315 
JsGetWidth(napi_env env,napi_callback_info info)1316 napi_value AVPlayerNapi::JsGetWidth(napi_env env, napi_callback_info info)
1317 {
1318     napi_value result = nullptr;
1319     napi_get_undefined(env, &result);
1320     MEDIA_LOGI("JsGetWidth In");
1321 
1322     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1323     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1324 
1325     int32_t width = 0;
1326     if (jsPlayer->IsControllable()) {
1327         width = jsPlayer->width_;
1328     }
1329 
1330     napi_value value = nullptr;
1331     (void)napi_create_int32(env, width, &value);
1332     MEDIA_LOGI("JsGetWidth Out");
1333     return value;
1334 }
1335 
JsGetHeight(napi_env env,napi_callback_info info)1336 napi_value AVPlayerNapi::JsGetHeight(napi_env env, napi_callback_info info)
1337 {
1338     napi_value result = nullptr;
1339     napi_get_undefined(env, &result);
1340     MEDIA_LOGI("JsGetHeight In");
1341 
1342     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1343     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1344 
1345     int32_t height = 0;
1346     if (jsPlayer->IsControllable()) {
1347         height = jsPlayer->height_;
1348     }
1349 
1350     napi_value value = nullptr;
1351     (void)napi_create_int32(env, height, &value);
1352     MEDIA_LOGI("JsGetHeight Out");
1353     return value;
1354 }
1355 
JsGetTrackDescription(napi_env env,napi_callback_info info)1356 napi_value AVPlayerNapi::JsGetTrackDescription(napi_env env, napi_callback_info info)
1357 {
1358     napi_value result = nullptr;
1359     napi_get_undefined(env, &result);
1360     MEDIA_LOGI("GetTrackDescription In");
1361 
1362     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1363     napi_value args[1] = { nullptr };
1364     size_t argCount = 1;
1365     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1366     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
1367     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
1368     // async work
1369     napi_value resource = nullptr;
1370     napi_create_string_utf8(env, "JsGetTrackDescription", NAPI_AUTO_LENGTH, &resource);
1371     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1372         [](napi_env env, void *data) {
1373             MEDIA_LOGI("GetTrackDescription Task");
1374             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1375             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1376 
1377             auto jsPlayer = promiseCtx->napi;
1378             if (jsPlayer == nullptr) {
1379                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
1380             }
1381 
1382             std::vector<Format> &trackInfo = jsPlayer->trackInfoVec_;
1383             trackInfo.clear();
1384             if (jsPlayer->IsControllable()) {
1385                 (void)jsPlayer->player_->GetVideoTrackInfo(trackInfo);
1386                 (void)jsPlayer->player_->GetAudioTrackInfo(trackInfo);
1387             } else {
1388                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1389                     "current state unsupport get track description");
1390             }
1391             promiseCtx->JsResult = std::make_unique<MediaJsResultArray>(trackInfo);
1392         },
1393         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1394     NAPI_CALL(env, napi_queue_async_work(env, promiseCtx->work));
1395     promiseCtx.release();
1396     MEDIA_LOGI("GetTrackDescription Out");
1397     return result;
1398 }
1399 
JsSetOnCallback(napi_env env,napi_callback_info info)1400 napi_value AVPlayerNapi::JsSetOnCallback(napi_env env, napi_callback_info info)
1401 {
1402     napi_value result = nullptr;
1403     napi_get_undefined(env, &result);
1404     MEDIA_LOGI("JsSetOnCallback In");
1405 
1406     napi_value args[2] = { nullptr }; // args[0]:type, args[1]:callback
1407     size_t argCount = 2; // args[0]:type, args[1]:callback
1408     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1409     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1410 
1411     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
1412         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to on event");
1413         return result;
1414     }
1415 
1416     napi_valuetype valueType0 = napi_undefined;
1417     napi_valuetype valueType1 = napi_undefined;
1418     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string ||
1419         args[1] == nullptr || napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
1420         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "napi_typeof failed, please check the input parameters");
1421         return result;
1422     }
1423 
1424     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
1425     MEDIA_LOGI("set callbackName: %{public}s", callbackName.c_str());
1426 
1427     napi_ref ref = nullptr;
1428     napi_status status = napi_create_reference(env, args[1], 1, &ref);
1429     CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
1430 
1431     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
1432     jsPlayer->SaveCallbackReference(callbackName, autoRef);
1433 
1434     MEDIA_LOGI("JsSetOnCallback Out");
1435     return result;
1436 }
1437 
JsClearOnCallback(napi_env env,napi_callback_info info)1438 napi_value AVPlayerNapi::JsClearOnCallback(napi_env env, napi_callback_info info)
1439 {
1440     napi_value result = nullptr;
1441     napi_get_undefined(env, &result);
1442     MEDIA_LOGI("JsClearOnCallback In");
1443 
1444     napi_value args[2] = { nullptr }; // args[0]:type, args[1]:callback
1445     size_t argCount = 2; // args[0]:type, args[1]:callback
1446     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1447     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1448 
1449     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
1450         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to off event");
1451         return result;
1452     }
1453 
1454     napi_valuetype valueType0 = napi_undefined;
1455     if (args[0] == nullptr || napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
1456         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "napi_typeof failed, please check the input parameters");
1457         return result;
1458     }
1459 
1460     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
1461     MEDIA_LOGI("set callbackName: %{public}s", callbackName.c_str());
1462 
1463     jsPlayer->ClearCallbackReference(callbackName);
1464     MEDIA_LOGI("JsClearOnCallback Out");
1465     return result;
1466 }
1467 
SaveCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)1468 void AVPlayerNapi::SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
1469 {
1470     std::lock_guard<std::mutex> lock(mutex_);
1471     refMap_[callbackName] = ref;
1472     if (playerCb_ != nullptr) {
1473         playerCb_->SaveCallbackReference(callbackName, ref);
1474     }
1475 }
1476 
ClearCallbackReference()1477 void AVPlayerNapi::ClearCallbackReference()
1478 {
1479     std::lock_guard<std::mutex> lock(mutex_);
1480     if (playerCb_ != nullptr) {
1481         playerCb_->ClearCallbackReference();
1482     }
1483     refMap_.clear();
1484 }
1485 
ClearCallbackReference(const std::string & callbackName)1486 void AVPlayerNapi::ClearCallbackReference(const std::string &callbackName)
1487 {
1488     std::lock_guard<std::mutex> lock(mutex_);
1489     if (playerCb_ != nullptr) {
1490         playerCb_->ClearCallbackReference(callbackName);
1491     }
1492     refMap_.erase(callbackName);
1493 }
1494 
NotifyDuration(int32_t duration)1495 void AVPlayerNapi::NotifyDuration(int32_t duration)
1496 {
1497     duration_ = duration;
1498 }
1499 
NotifyPosition(int32_t position)1500 void AVPlayerNapi::NotifyPosition(int32_t position)
1501 {
1502     position_ = position;
1503 }
1504 
NotifyState(PlayerStates state)1505 void AVPlayerNapi::NotifyState(PlayerStates state)
1506 {
1507     std::lock_guard<std::mutex> lock(taskMutex_);
1508     if (state_ != state) {
1509         state_ = state;
1510         MEDIA_LOGI("notify %{public}s OK", GetCurrentState().c_str());
1511         switch (state_) {
1512             case PLAYER_PREPARED:
1513                 preparingCond_.notify_all();
1514                 break;
1515             case PLAYER_IDLE:
1516                 resettingCond_.notify_all();
1517                 break;
1518             case PLAYER_STARTED:
1519             case PLAYER_PAUSED:
1520             case PLAYER_STOPPED:
1521             case PLAYER_PLAYBACK_COMPLETE:
1522                 stateChangeCond_.notify_all();
1523                 break;
1524             case PLAYER_STATE_ERROR:
1525                 preparingCond_.notify_all();
1526                 resettingCond_.notify_all();
1527                 stateChangeCond_.notify_all();
1528                 break;
1529             default:
1530                 break;
1531         }
1532     }
1533 }
1534 
NotifyVideoSize(int32_t width,int32_t height)1535 void AVPlayerNapi::NotifyVideoSize(int32_t width, int32_t height)
1536 {
1537     width_ = width;
1538     height_ = height;
1539 }
1540 
ResetUserParameters()1541 void AVPlayerNapi::ResetUserParameters()
1542 {
1543     url_.clear();
1544     fileDescriptor_.fd = 0;
1545     fileDescriptor_.offset = 0;
1546     fileDescriptor_.length = -1;
1547     width_ = 0;
1548     height_ = 0;
1549     position_ = -1;
1550     duration_ = -1;
1551     loop_ = false;
1552 }
1553 
StartListenCurrentResource()1554 void AVPlayerNapi::StartListenCurrentResource()
1555 {
1556     std::lock_guard<std::mutex> lock(mutex_);
1557     if (playerCb_ != nullptr) {
1558         playerCb_->Start();
1559     }
1560 }
1561 
PauseListenCurrentResource()1562 void AVPlayerNapi::PauseListenCurrentResource()
1563 {
1564     std::lock_guard<std::mutex> lock(mutex_);
1565     if (playerCb_ != nullptr) {
1566         playerCb_->Pause();
1567     }
1568 }
1569 
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)1570 void AVPlayerNapi::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
1571 {
1572     std::lock_guard<std::mutex> lock(mutex_);
1573     if (playerCb_ != nullptr) {
1574         playerCb_->OnErrorCb(errorCode, errorMsg);
1575     }
1576 }
1577 
GetJsInstance(napi_env env,napi_callback_info info)1578 AVPlayerNapi* AVPlayerNapi::GetJsInstance(napi_env env, napi_callback_info info)
1579 {
1580     size_t argCount = 0;
1581     napi_value jsThis = nullptr;
1582     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
1583     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
1584 
1585     AVPlayerNapi *jsPlayer = nullptr;
1586     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
1587     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
1588 
1589     return jsPlayer;
1590 }
1591 
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)1592 AVPlayerNapi* AVPlayerNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
1593     size_t &argc, napi_value *argv)
1594 {
1595     napi_value jsThis = nullptr;
1596     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
1597     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
1598 
1599     AVPlayerNapi *jsPlayer = nullptr;
1600     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
1601     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
1602 
1603     return jsPlayer;
1604 }
1605 } // namespace Media
1606 } // namespace OHOS