• 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_errors.h"
19 #include "common_napi.h"
20 #include "js_common_utils.h"
21 #ifdef SUPPORT_AVPLAYER_DRM
22 #include "key_session_impl.h"
23 #endif
24 #ifdef SUPPORT_VIDEO
25 #include "surface_utils.h"
26 #endif
27 #include "string_ex.h"
28 #include "player_xcollie.h"
29 #include "media_dfx.h"
30 #ifdef SUPPORT_JSSTACK
31 #include "xpower_event_js.h"
32 #endif
33 #include "av_common.h"
34 #include "meta/video_types.h"
35 #include "media_source_napi.h"
36 #include "media_log.h"
37 #ifndef CROSS_PLATFORM
38 #include "ipc_skeleton.h"
39 #include "tokenid_kit.h"
40 #endif
41 
42 using namespace OHOS::AudioStandard;
43 
44 namespace {
45     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "AVPlayerNapi" };
46     constexpr uint32_t MIN_ARG_COUNTS = 1;
47     constexpr uint32_t MAX_ARG_COUNTS = 2;
48     constexpr size_t ARRAY_ARG_COUNTS_TWO = 2;
49     constexpr size_t ARRAY_ARG_COUNTS_THREE = 3;
50     constexpr int32_t PLAY_RANGE_DEFAULT_VALUE = -1;
51     constexpr int32_t SEEK_MODE_CLOSEST = 2;
52     constexpr int32_t INDEX_A = 0;
53     constexpr int32_t INDEX_B = 1;
54     constexpr int32_t INDEX_C = 2;
55     constexpr uint32_t TASK_TIME_LIMIT_MS = 2000; // ms
56     constexpr size_t PARAM_COUNT_SINGLE = 1;
57     constexpr int32_t API_VERSION_17 = 17;
58     static int32_t g_apiVersion = -1;
59     constexpr int32_t ARGS_TWO = 2;
60     constexpr int32_t ARGS_THREE = 3;
61     constexpr int32_t SEEK_CONTINUOUS_TS_ENUM_NUM = 3;
62     constexpr double RATE_DEFAULT_VALUE = 1.0;
63 }
64 
65 namespace OHOS {
66 namespace Media {
67 thread_local napi_ref AVPlayerNapi::constructor_ = nullptr;
68 const std::string CLASS_NAME = "AVPlayer";
69 
AVPlayerNapi()70 AVPlayerNapi::AVPlayerNapi()
71 {
72     MEDIA_LOGI("0x%{public}06" PRIXPTR " ctor", FAKE_POINTER(this));
73 }
74 
~AVPlayerNapi()75 AVPlayerNapi::~AVPlayerNapi()
76 {
77     MEDIA_LOGI("0x%{public}06" PRIXPTR " dtor", FAKE_POINTER(this));
78 }
79 
Init(napi_env env,napi_value exports)80 napi_value AVPlayerNapi::Init(napi_env env, napi_value exports)
81 {
82     napi_property_descriptor staticProperty[] = {
83         DECLARE_NAPI_STATIC_FUNCTION("createAVPlayer", JsCreateAVPlayer),
84     };
85 
86     napi_property_descriptor properties[] = {
87         DECLARE_NAPI_FUNCTION("prepare", JsPrepare),
88         DECLARE_NAPI_FUNCTION("play", JsPlay),
89         DECLARE_NAPI_FUNCTION("pause", JsPause),
90         DECLARE_NAPI_FUNCTION("stop", JsStop),
91         DECLARE_NAPI_FUNCTION("reset", JsReset),
92         DECLARE_NAPI_FUNCTION("release", JsRelease),
93         DECLARE_NAPI_FUNCTION("seek", JsSeek),
94         DECLARE_NAPI_FUNCTION("setPlaybackRange", JsSetPlaybackRange),
95         DECLARE_NAPI_FUNCTION("setSuperResolution", JsSetSuperResolution),
96         DECLARE_NAPI_FUNCTION("setVideoWindowSize", JsSetVideoWindowSize),
97         DECLARE_NAPI_FUNCTION("enableCameraPostprocessing", JsEnableCameraPostprocessing),
98         DECLARE_NAPI_FUNCTION("on", JsSetOnCallback),
99         DECLARE_NAPI_FUNCTION("off", JsClearOnCallback),
100         DECLARE_NAPI_FUNCTION("setVolume", JsSetVolume),
101         DECLARE_NAPI_FUNCTION("setSpeed", JsSetSpeed),
102         DECLARE_NAPI_FUNCTION("setPlaybackRate", JsSetPlaybackRate),
103         DECLARE_NAPI_FUNCTION("setMediaSource", JsSetMediaSource),
104         DECLARE_NAPI_FUNCTION("setBitrate", JsSelectBitrate),
105         DECLARE_NAPI_FUNCTION("getTrackDescription", JsGetTrackDescription),
106         DECLARE_NAPI_FUNCTION("getSelectedTracks", JsGetSelectedTracks),
107         DECLARE_NAPI_FUNCTION("selectTrack", JsSelectTrack),
108         DECLARE_NAPI_FUNCTION("deselectTrack", JsDeselectTrack),
109         DECLARE_NAPI_FUNCTION("getCurrentTrack", JsGetCurrentTrack),
110         DECLARE_NAPI_FUNCTION("addSubtitleUrl", JsAddSubtitleUrl),
111         DECLARE_NAPI_FUNCTION("addSubtitleFdSrc", JsAddSubtitleAVFileDescriptor),
112         DECLARE_NAPI_FUNCTION("addSubtitleFromUrl", JsAddSubtitleUrl),
113         DECLARE_NAPI_FUNCTION("addSubtitleFromFd", JsAddSubtitleAVFileDescriptor),
114         DECLARE_NAPI_FUNCTION("setDecryptionConfig", JsSetDecryptConfig),
115         DECLARE_NAPI_FUNCTION("getMediaKeySystemInfos", JsGetMediaKeySystemInfos),
116         DECLARE_NAPI_FUNCTION("setPlaybackStrategy", JsSetPlaybackStrategy),
117         DECLARE_NAPI_FUNCTION("setMediaMuted", JsSetMediaMuted),
118         DECLARE_NAPI_FUNCTION("getPlaybackInfo", JsGetPlaybackInfo),
119         DECLARE_NAPI_FUNCTION("isSeekContinuousSupported", JsIsSeekContinuousSupported),
120         DECLARE_NAPI_FUNCTION("getPlaybackPosition", JsGetPlaybackPosition),
121         DECLARE_NAPI_FUNCTION("forceLoadVideo", JsForceLoadVideo),
122 
123         DECLARE_NAPI_GETTER_SETTER("url", JsGetUrl, JsSetUrl),
124         DECLARE_NAPI_GETTER_SETTER("fdSrc", JsGetAVFileDescriptor, JsSetAVFileDescriptor),
125         DECLARE_NAPI_GETTER_SETTER("dataSrc", JsGetDataSrc, JsSetDataSrc),
126         DECLARE_NAPI_GETTER_SETTER("surfaceId", JsGetSurfaceID, JsSetSurfaceID),
127         DECLARE_NAPI_GETTER_SETTER("loop", JsGetLoop, JsSetLoop),
128         DECLARE_NAPI_GETTER_SETTER("videoScaleType", JsGetVideoScaleType, JsSetVideoScaleType),
129         DECLARE_NAPI_GETTER_SETTER("audioInterruptMode", JsGetAudioInterruptMode, JsSetAudioInterruptMode),
130         DECLARE_NAPI_GETTER_SETTER("audioRendererInfo", JsGetAudioRendererInfo, JsSetAudioRendererInfo),
131         DECLARE_NAPI_GETTER_SETTER("audioEffectMode", JsGetAudioEffectMode, JsSetAudioEffectMode),
132 
133         DECLARE_NAPI_SETTER("enableStartFrameRateOpt", JsSetStartFrameRateOptEnabled),
134         DECLARE_NAPI_GETTER("state", JsGetState),
135         DECLARE_NAPI_GETTER("currentTime", JsGetCurrentTime),
136         DECLARE_NAPI_GETTER("duration", JsGetDuration),
137         DECLARE_NAPI_GETTER("width", JsGetWidth),
138         DECLARE_NAPI_GETTER("height", JsGetHeight),
139     };
140     napi_value constructor = nullptr;
141     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
142         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
143     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVPlayer class");
144 
145     status = napi_create_reference(env, constructor, 1, &constructor_);
146     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
147 
148     status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
149     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
150 
151     status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
152     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
153     return exports;
154 }
155 
Constructor(napi_env env,napi_callback_info info)156 napi_value AVPlayerNapi::Constructor(napi_env env, napi_callback_info info)
157 {
158     napi_value result = nullptr;
159     napi_get_undefined(env, &result);
160 
161     size_t argCount = 0;
162     napi_value jsThis = nullptr;
163     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
164     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
165 
166     AVPlayerNapi *jsPlayer = new(std::nothrow) AVPlayerNapi();
167     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to new AVPlayerNapi");
168 
169     jsPlayer->env_ = env;
170     jsPlayer->player_ = PlayerFactory::CreatePlayer(PlayerProducer::NAPI);
171     if (jsPlayer->player_ == nullptr) {
172         delete jsPlayer;
173         MEDIA_LOGE("failed to CreatePlayer");
174         return result;
175     }
176 
177     jsPlayer->taskQue_ = std::make_unique<TaskQueue>("OS_AVPlayerNapi");
178     (void)jsPlayer->taskQue_->Start();
179 
180     jsPlayer->playerCb_ = std::make_shared<AVPlayerCallback>(env, jsPlayer);
181     (void)jsPlayer->player_->SetPlayerCallback(jsPlayer->playerCb_);
182 
183     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsPlayer),
184         AVPlayerNapi::Destructor, nullptr, nullptr);
185     if (status != napi_ok) {
186         delete jsPlayer;
187         MEDIA_LOGE("Failed to wrap native instance");
188         return result;
189     }
190 
191     MEDIA_LOGI("0x%{public}06" PRIXPTR " Constructor success", FAKE_POINTER(jsPlayer));
192     return jsThis;
193 }
194 
Destructor(napi_env env,void * nativeObject,void * finalize)195 void AVPlayerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
196 {
197     (void)env;
198     (void)finalize;
199     if (nativeObject != nullptr) {
200         AVPlayerNapi *jsPlayer = reinterpret_cast<AVPlayerNapi *>(nativeObject);
201         jsPlayer->ClearCallbackReference();
202         std::thread([jsPlayer]() -> void {
203             auto task = jsPlayer->ReleaseTask();
204             if (task != nullptr) {
205                 MEDIA_LOGI("0x%{public}06" PRIXPTR " Destructor wait >>", FAKE_POINTER(jsPlayer));
206                 task->GetResult(); // sync release
207                 MEDIA_LOGI("0x%{public}06" PRIXPTR " Destructor wait <<", FAKE_POINTER(jsPlayer));
208             }
209             jsPlayer->WaitTaskQueStop();
210             delete jsPlayer;
211         }).detach();
212     }
213     MEDIA_LOGD("Destructor success");
214 }
215 
IsSystemApp()216 bool AVPlayerNapi::IsSystemApp()
217 {
218     static bool isSystemApp = false;
219 #ifndef CROSS_PLATFORM
220     static std::once_flag once;
221     std::call_once(once, [] {
222         uint64_t tokenId = IPCSkeleton::GetSelfTokenID();
223         isSystemApp = Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
224     });
225 #endif
226     return isSystemApp;
227 }
228 
JsCreateAVPlayer(napi_env env,napi_callback_info info)229 napi_value AVPlayerNapi::JsCreateAVPlayer(napi_env env, napi_callback_info info)
230 {
231     MediaTrace trace("AVPlayerNapi::createAVPlayer");
232     napi_value result = nullptr;
233     napi_get_undefined(env, &result);
234     MEDIA_LOGD("JsCreateAVPlayer In");
235 
236     std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
237 
238     // get args
239     napi_value jsThis = nullptr;
240     napi_value args[1] = { nullptr };
241     size_t argCount = 1;
242     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
243     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
244 
245     asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
246     asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
247     asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
248     asyncContext->ctorFlag = true;
249 
250     auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncContext.get(), napi_eprio_immediate);
251     if (ret != napi_status::napi_ok) {
252         MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
253     } else {
254         asyncContext.release();
255     }
256     MEDIA_LOGD("0x%{public}06" PRIXPTR " JsCreateAVPlayer Out", FAKE_POINTER(jsThis));
257     return result;
258 }
259 
PrepareTask()260 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PrepareTask()
261 {
262     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
263         MEDIA_LOGI("0x%{public}06" PRIXPTR " Prepare Task In", FAKE_POINTER(this));
264         std::unique_lock<std::mutex> lock(taskMutex_);
265         auto state = GetCurrentState();
266         if (state == AVPlayerState::STATE_INITIALIZED ||
267             state == AVPlayerState::STATE_STOPPED) {
268             int32_t ret = player_->PrepareAsync();
269             if (ret != MSERR_OK) {
270                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
271                 return TaskRet(errCode, "failed to prepare");
272             }
273             stopWait_ = false;
274             stateChangeCond_.wait(lock, [this]() {
275                 return stopWait_.load() || isInterrupted_.load() || avplayerExit_;
276             });
277 
278             if (GetCurrentState() == AVPlayerState::STATE_ERROR) {
279                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
280                     "failed to prepare, avplayer enter error status, please check error callback messages!");
281             }
282         } else if (state == AVPlayerState::STATE_PREPARED) {
283             MEDIA_LOGI("current state is prepared, invalid operation");
284         } else {
285             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
286                 "current state is not stopped or initialized, unsupport prepare operation");
287         }
288 
289         MEDIA_LOGI("0x%{public}06" PRIXPTR " Prepare Task Out", FAKE_POINTER(this));
290         return TaskRet(MSERR_EXT_API9_OK, "Success");
291     });
292 
293     (void)taskQue_->EnqueueTask(task);
294     return task;
295 }
296 
JsPrepare(napi_env env,napi_callback_info info)297 napi_value AVPlayerNapi::JsPrepare(napi_env env, napi_callback_info info)
298 {
299     MediaTrace trace("AVPlayerNapi::prepare");
300     napi_value result = nullptr;
301     napi_get_undefined(env, &result);
302     MEDIA_LOGI("JsPrepare 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_INITIALIZED &&
314         state != AVPlayerState::STATE_STOPPED &&
315         state != AVPlayerState::STATE_PREPARED) {
316         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
317             "current state is not stopped or initialized, unsupport prepare operation");
318     } else {
319         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPrepare EnqueueTask In", FAKE_POINTER(jsPlayer));
320         promiseCtx->asyncTask = jsPlayer->PrepareTask();
321         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPrepare EnqueueTask out", FAKE_POINTER(jsPlayer));
322     }
323 
324     napi_value resource = nullptr;
325     napi_create_string_utf8(env, "JsPrepare", NAPI_AUTO_LENGTH, &resource);
326     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
327         [](napi_env env, void *data) {
328             MEDIA_LOGI("Wait Prepare Task Start");
329             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
330             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
331             promiseCtx->CheckTaskResult(true, TASK_TIME_LIMIT_MS);
332             MEDIA_LOGI("Wait Prepare Task End");
333         },
334         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
335     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
336     promiseCtx.release();
337     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPrepare Out", FAKE_POINTER(jsPlayer));
338     return result;
339 }
340 
PlayTask()341 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PlayTask()
342 {
343     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
344         MEDIA_LOGI("0x%{public}06" PRIXPTR " Play Task In", FAKE_POINTER(this));
345         std::unique_lock<std::mutex> lock(taskMutex_);
346         auto state = GetCurrentState();
347         if (state == AVPlayerState::STATE_PREPARED ||
348             state == AVPlayerState::STATE_PAUSED ||
349             state == AVPlayerState::STATE_COMPLETED) {
350             int32_t ret = player_->Play();
351             if (ret != MSERR_OK) {
352                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
353                 return TaskRet(errCode, "failed to Play");
354             }
355             stopWait_ = false;
356             stateChangeCond_.wait(lock, [this]() {
357                 return stopWait_.load() || isInterrupted_.load() || avplayerExit_;
358             });
359 
360             if (GetCurrentState() == AVPlayerState::STATE_ERROR) {
361                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
362                     "failed to play, avplayer enter error status, please check error callback messages!");
363             }
364         } else if (state == AVPlayerState::STATE_PLAYING) {
365             if (IsSystemApp()) {
366                 player_->Seek(-1, SEEK_CONTINOUS);
367             }
368             MEDIA_LOGI("current state is playing, invalid operation");
369         } else {
370             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
371                 "current state is not prepared/paused/completed, unsupport play operation");
372         }
373 
374         MEDIA_LOGI("0x%{public}06" PRIXPTR " Play Task Out", FAKE_POINTER(this));
375         return TaskRet(MSERR_EXT_API9_OK, "Success");
376     });
377     (void)taskQue_->EnqueueTask(task);
378     return task;
379 }
380 
JsPlay(napi_env env,napi_callback_info info)381 napi_value AVPlayerNapi::JsPlay(napi_env env, napi_callback_info info)
382 {
383     MediaTrace trace("AVPlayerNapi::play");
384     napi_value result = nullptr;
385     napi_get_undefined(env, &result);
386     MEDIA_LOGI("JsPlay In");
387 
388     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
389     napi_value args[1] = { nullptr };
390     size_t argCount = 1;
391     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
392     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
393 
394     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
395     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
396     auto state = jsPlayer->GetCurrentState();
397     if (state != AVPlayerState::STATE_PREPARED &&
398         state != AVPlayerState::STATE_PAUSED &&
399         state != AVPlayerState::STATE_COMPLETED &&
400         state != AVPlayerState::STATE_PLAYING) {
401         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
402             "current state is not prepared/paused/completed, unsupport play operation");
403     } else if (state == AVPlayerState::STATE_COMPLETED && jsPlayer->IsLiveSource()) {
404         promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_CAPABILITY,
405             "In live mode, replay not be allowed.");
406     } else {
407         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPlay EnqueueTask In", FAKE_POINTER(jsPlayer));
408         promiseCtx->asyncTask = jsPlayer->PlayTask();
409         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPlay EnqueueTask Out", FAKE_POINTER(jsPlayer));
410     }
411 #ifdef SUPPORT_JSSTACK
412     HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
413 #endif
414     napi_value resource = nullptr;
415     napi_create_string_utf8(env, "JsPlay", NAPI_AUTO_LENGTH, &resource);
416     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
417         [](napi_env env, void *data) {
418             MEDIA_LOGI("Wait JsPlay Task Start");
419             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
420             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
421             promiseCtx->CheckTaskResult(true, TASK_TIME_LIMIT_MS);
422             MEDIA_LOGI("Wait JsPlay Task End");
423         },
424         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
425     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
426     promiseCtx.release();
427     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPlay Out", FAKE_POINTER(jsPlayer));
428     return result;
429 }
430 
PauseTask()431 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PauseTask()
432 {
433     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
434         MEDIA_LOGI("0x%{public}06" PRIXPTR " Pause Task In", FAKE_POINTER(this));
435         std::unique_lock<std::mutex> lock(taskMutex_);
436         auto state = GetCurrentState();
437         if (state == AVPlayerState::STATE_PLAYING) {
438             int32_t ret = player_->Pause();
439             if (ret != MSERR_OK) {
440                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
441                 return TaskRet(errCode, "failed to Pause");
442             }
443             stopWait_ = false;
444             stateChangeCond_.wait(lock, [this]() { return stopWait_.load() || avplayerExit_; });
445         } else if (state == AVPlayerState::STATE_PAUSED) {
446             MEDIA_LOGI("current state is paused, invalid operation");
447         } else {
448             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
449                 "current state is not playing, unsupport pause operation");
450         }
451 
452         MEDIA_LOGI("0x%{public}06" PRIXPTR " Pause Task Out", FAKE_POINTER(this));
453         return TaskRet(MSERR_EXT_API9_OK, "Success");
454     });
455     (void)taskQue_->EnqueueTask(task);
456     return task;
457 }
458 
JsPause(napi_env env,napi_callback_info info)459 napi_value AVPlayerNapi::JsPause(napi_env env, napi_callback_info info)
460 {
461     MediaTrace trace("AVPlayerNapi::pause");
462     napi_value result = nullptr;
463     napi_get_undefined(env, &result);
464     MEDIA_LOGI("JsPause In");
465 
466     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
467     napi_value args[1] = { nullptr };
468     size_t argCount = 1;
469     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
470     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
471 
472     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
473     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
474     auto state = jsPlayer->GetCurrentState();
475     if (state != AVPlayerState::STATE_PLAYING &&
476         state != AVPlayerState::STATE_PAUSED) {
477         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
478             "current state is not playing, unsupport pause operation");
479     } else {
480         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPause EnqueueTask In", FAKE_POINTER(jsPlayer));
481         promiseCtx->asyncTask = jsPlayer->PauseTask();
482         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPause EnqueueTask Out", FAKE_POINTER(jsPlayer));
483     }
484 
485     napi_value resource = nullptr;
486     napi_create_string_utf8(env, "JsPause", NAPI_AUTO_LENGTH, &resource);
487     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
488         [](napi_env env, void *data) {
489             MEDIA_LOGI("Wait JsPause Task Start");
490             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
491             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
492             promiseCtx->CheckTaskResult();
493             MEDIA_LOGI("Wait JsPause Task End");
494         },
495         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
496     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
497     promiseCtx.release();
498     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsPause Out", FAKE_POINTER(jsPlayer));
499     return result;
500 }
501 
StopTask()502 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::StopTask()
503 {
504     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
505         MEDIA_LOGI("0x%{public}06" PRIXPTR " Stop Task In", FAKE_POINTER(this));
506         std::unique_lock<std::mutex> lock(taskMutex_);
507         if (IsControllable()) {
508             int32_t ret = player_->Stop();
509             if (ret != MSERR_OK) {
510                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
511                 return TaskRet(errCode, "failed to Stop");
512             }
513             stopWait_ = false;
514             stateChangeCond_.wait(lock, [this]() { return stopWait_.load() || avplayerExit_; });
515         } else if (GetCurrentState() == AVPlayerState::STATE_STOPPED) {
516             MEDIA_LOGI("current state is stopped, invalid operation");
517         }  else {
518             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
519                 "current state is not prepared/playing/paused/completed, unsupport stop operation");
520         }
521 
522         MEDIA_LOGI("0x%{public}06" PRIXPTR " Stop Task Out", FAKE_POINTER(this));
523         return TaskRet(MSERR_EXT_API9_OK, "Success");
524     });
525     (void)taskQue_->EnqueueTask(task);
526     return task;
527 }
528 
JsStop(napi_env env,napi_callback_info info)529 napi_value AVPlayerNapi::JsStop(napi_env env, napi_callback_info info)
530 {
531     MediaTrace trace("AVPlayerNapi::stop");
532     napi_value result = nullptr;
533     napi_get_undefined(env, &result);
534     MEDIA_LOGI("JsStop In");
535 
536     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
537     napi_value args[1] = { nullptr };
538     size_t argCount = 1;
539     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
540     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
541 
542     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
543     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
544     auto state = jsPlayer->GetCurrentState();
545     if (state == AVPlayerState::STATE_IDLE ||
546         state == AVPlayerState::STATE_INITIALIZED ||
547         state == AVPlayerState::STATE_RELEASED ||
548         state == AVPlayerState::STATE_ERROR) {
549         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
550             "current state is not prepared/playing/paused/completed, unsupport stop operation");
551     } else {
552         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsStop EnqueueTask In", FAKE_POINTER(jsPlayer));
553         promiseCtx->asyncTask = jsPlayer->StopTask();
554         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsStop EnqueueTask Out", FAKE_POINTER(jsPlayer));
555     }
556 
557     napi_value resource = nullptr;
558     napi_create_string_utf8(env, "JsStop", NAPI_AUTO_LENGTH, &resource);
559     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
560         [](napi_env env, void *data) {
561             MEDIA_LOGI("Wait JsStop Task Start");
562             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
563             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
564             promiseCtx->CheckTaskResult();
565             MEDIA_LOGI("Wait JsStop Task End");
566         },
567         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
568     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
569     promiseCtx.release();
570     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsStop Out", FAKE_POINTER(jsPlayer));
571     return result;
572 }
573 
ResetTask()574 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ResetTask()
575 {
576     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
577         MEDIA_LOGI("0x%{public}06" PRIXPTR " Reset Task In", FAKE_POINTER(this));
578         PauseListenCurrentResource(); // Pause event listening for the current resource
579         ResetUserParameters();
580         {
581             isInterrupted_.store(false);
582             std::unique_lock<std::mutex> lock(taskMutex_);
583             if (GetCurrentState() == AVPlayerState::STATE_RELEASED) {
584                 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
585                     "current state is not playing, unsupport pause operation");
586             } else if (GetCurrentState() == AVPlayerState::STATE_IDLE) {
587                 MEDIA_LOGI("current state is idle, invalid operation");
588             } else {
589                 int32_t ret = player_->Reset();
590                 if (ret != MSERR_OK) {
591                     auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
592                     return TaskRet(errCode, "failed to Reset");
593                 }
594                 stopWait_ = false;
595                 stateChangeCond_.wait(lock, [this]() { return stopWait_.load() || avplayerExit_; });
596             }
597         }
598         MEDIA_LOGI("0x%{public}06" PRIXPTR " Reset Task Out", FAKE_POINTER(this));
599         return TaskRet(MSERR_EXT_API9_OK, "Success");
600     });
601     (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
602     isInterrupted_.store(true);
603     stateChangeCond_.notify_all();
604     return task;
605 }
606 
JsReset(napi_env env,napi_callback_info info)607 napi_value AVPlayerNapi::JsReset(napi_env env, napi_callback_info info)
608 {
609     MediaTrace trace("AVPlayerNapi::reset");
610     napi_value result = nullptr;
611     napi_get_undefined(env, &result);
612     MEDIA_LOGI("JsReset In");
613 
614     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
615     napi_value args[1] = { nullptr };
616     size_t argCount = 1;
617     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
618     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
619     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
620     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
621     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
622         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
623             "current state is released, unsupport reset operation");
624     } else {
625         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsReset EnqueueTask In", FAKE_POINTER(jsPlayer));
626         promiseCtx->asyncTask = jsPlayer->ResetTask();
627         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsReset EnqueueTask Out", FAKE_POINTER(jsPlayer));
628         if (jsPlayer->dataSrcCb_ != nullptr) {
629             jsPlayer->dataSrcCb_->ClearCallbackReference();
630             jsPlayer->dataSrcCb_ = nullptr;
631         }
632         jsPlayer->isLiveStream_ = false;
633     }
634 
635     napi_value resource = nullptr;
636     napi_create_string_utf8(env, "JsReset", NAPI_AUTO_LENGTH, &resource);
637     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
638         [](napi_env env, void *data) {
639             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
640             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
641             if (promiseCtx->asyncTask != nullptr) {
642                 MEDIA_LOGI("Wait Reset Task Start");
643                 promiseCtx->CheckTaskResult();
644                 MEDIA_LOGI("Wait Reset Task Stop");
645             }
646         },
647         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
648     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
649     promiseCtx.release();
650     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsReset Out", FAKE_POINTER(jsPlayer));
651     return result;
652 }
653 
WaitTaskQueStop()654 void AVPlayerNapi::WaitTaskQueStop()
655 {
656     MEDIA_LOGI("0x%{public}06" PRIXPTR " WaitTaskQueStop In", FAKE_POINTER(this));
657     std::unique_lock<std::mutex> lock(mutex_);
658     stopTaskQueCond_.wait(lock, [this]() { return taskQueStoped_; });
659     MEDIA_LOGI("0x%{public}06" PRIXPTR " WaitTaskQueStop Out", FAKE_POINTER(this));
660 }
661 
StopTaskQue()662 void AVPlayerNapi::StopTaskQue()
663 {
664     MEDIA_LOGI("0x%{public}06" PRIXPTR " StopTaskQue In", FAKE_POINTER(this));
665     {
666         std::unique_lock<std::mutex> lock(taskMutex_);
667         avplayerExit_ = true;
668     }
669     stateChangeCond_.notify_all();
670     taskQue_->Stop();
671     std::unique_lock<std::mutex> lock(mutex_);
672     taskQueStoped_ = true;
673     stopTaskQueCond_.notify_all();
674     MEDIA_LOGI("0x%{public}06" PRIXPTR " StopTaskQue Out", FAKE_POINTER(this));
675 }
676 
ReleaseTask()677 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ReleaseTask()
678 {
679     std::shared_ptr<TaskHandler<TaskRet>> task = nullptr;
680     if (!isReleased_.load()) {
681         task = std::make_shared<TaskHandler<TaskRet>>([this]() {
682             MEDIA_LOGI("0x%{public}06" PRIXPTR " Release Task In", FAKE_POINTER(this));
683             PauseListenCurrentResource(); // Pause event listening for the current resource
684             ResetUserParameters();
685 
686             {
687                 std::lock_guard<std::mutex> lock(syncMutex_);
688                 if (player_ != nullptr) {
689                     (void)player_->ReleaseSync();
690                     player_ = nullptr;
691                 }
692             }
693 
694             if (playerCb_ != nullptr) {
695                 playerCb_->Release();
696             }
697             MEDIA_LOGI("0x%{public}06" PRIXPTR " Release Task Out", FAKE_POINTER(this));
698             std::thread([this] () -> void { this->StopTaskQue(); }).detach();
699             return TaskRet(MSERR_EXT_API9_OK, "Success");
700         });
701 
702         isReleased_.store(true);
703         (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
704         if (taskQue_->IsTaskExecuting()) {
705             MEDIA_LOGW("0x%{public}06" PRIXPTR " Cancel Executing Task, ReleaseTask Report Error", FAKE_POINTER(this));
706             NotifyState(PlayerStates::PLAYER_STATE_ERROR);
707         }
708     }
709     return task;
710 }
711 
JsRelease(napi_env env,napi_callback_info info)712 napi_value AVPlayerNapi::JsRelease(napi_env env, napi_callback_info info)
713 {
714     MediaTrace trace("AVPlayerNapi::release");
715     napi_value result = nullptr;
716     napi_get_undefined(env, &result);
717     MEDIA_LOGI("JsRelease In");
718 
719     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
720     napi_value args[1] = { nullptr };
721     size_t argCount = 1;
722     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
723     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
724     jsPlayer->isReadyReleased_.store(true);
725     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
726     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
727     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsRelease EnqueueTask In", FAKE_POINTER(jsPlayer));
728     promiseCtx->asyncTask = jsPlayer->ReleaseTask();
729     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsRelease EnqueueTask Out", FAKE_POINTER(jsPlayer));
730     if (jsPlayer->dataSrcCb_ != nullptr) {
731         jsPlayer->dataSrcCb_->ClearCallbackReference();
732         jsPlayer->dataSrcCb_ = nullptr;
733     }
734 
735     napi_value resource = nullptr;
736     napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
737     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
738         [](napi_env env, void *data) {
739             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
740             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
741             if (promiseCtx->asyncTask != nullptr) {
742                 MEDIA_LOGI("Wait Release Task Start");
743                 promiseCtx->CheckTaskResult();
744                 MEDIA_LOGI("Wait Release Task Stop");
745             }
746         },
747         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
748     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
749     promiseCtx.release();
750     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsRelease Out", FAKE_POINTER(jsPlayer));
751     return result;
752 }
753 
JsSeek(napi_env env,napi_callback_info info)754 napi_value AVPlayerNapi::JsSeek(napi_env env, napi_callback_info info)
755 {
756     MediaTrace trace("AVPlayerNapi::seek");
757     MEDIA_LOGI("JsSeek in");
758     napi_value result = nullptr;
759     napi_get_undefined(env, &result);
760     napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr }; // args[0]:timeMs, args[1]:SeekMode
761     size_t argCount = 2; // args[0]:timeMs, args[1]:SeekMode
762     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
763     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
764     if (jsPlayer->IsLiveSource()) {
765         jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support seek");
766         return result;
767     }
768     napi_valuetype valueType = napi_undefined;
769     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
770         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek time is not number");
771         return result;
772     }
773     int32_t time = -1;
774     napi_status status = napi_get_value_int32(env, args[0], &time);
775     if (status != napi_ok || (time < 0 && argCount == 1)) {
776         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check seek time");
777         return result;
778     }
779     int32_t mode = SEEK_PREVIOUS_SYNC;
780     if (argCount > 1) {
781         if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
782             jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek mode is not number");
783             return result;
784         }
785         status = napi_get_value_int32(env, args[1], &mode);
786         if (status != napi_ok || mode < SEEK_NEXT_SYNC || mode > SEEK_CONTINUOUS_TS_ENUM_NUM) {
787             jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check seek mode");
788             return result;
789         }
790         bool isNegativeTime = time < 0;
791         bool isExitSeekContinuous = time == -1 && mode == SEEK_CONTINUOUS_TS_ENUM_NUM;
792         if (isNegativeTime && !isExitSeekContinuous) {
793             jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check seek time");
794             return result;
795         }
796     }
797     if (!jsPlayer->IsControllable()) {
798         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
799             "current state is not prepared/playing/paused/completed, unsupport seek operation");
800         return result;
801     }
802     SeekEnqueueTask(jsPlayer, time, mode);
803     return result;
804 }
805 
TransferSeekMode(int32_t mode)806 PlayerSeekMode AVPlayerNapi::TransferSeekMode(int32_t mode)
807 {
808     MEDIA_LOGI("Seek Task TransferSeekMode, mode: %{public}d", mode);
809     PlayerSeekMode seekMode = PlayerSeekMode::SEEK_PREVIOUS_SYNC;
810     switch (mode) {
811         case 0: // Seek to the next sync frame of the given timestamp.
812             seekMode = PlayerSeekMode::SEEK_NEXT_SYNC;
813             break;
814         case 1: // Seek to the previous sync frame of the given timestamp.
815             seekMode = PlayerSeekMode::SEEK_PREVIOUS_SYNC;
816             break;
817         case 2: // Seek to the closest frame of the given timestamp. 2 refers SeekMode in @ohos.multimedia.media.d.ts
818             seekMode = PlayerSeekMode::SEEK_CLOSEST;
819             break;
820         case 3: // Seek continous of the given timestamp. 3 refers SeekMode in @ohos.multimedia.media.d.ts
821             seekMode = PlayerSeekMode::SEEK_CONTINOUS;
822             break;
823         default:
824             seekMode = PlayerSeekMode::SEEK_PREVIOUS_SYNC;
825             break;
826     }
827     return seekMode;
828 }
829 
JsSetPlaybackRange(napi_env env,napi_callback_info info)830 napi_value AVPlayerNapi::JsSetPlaybackRange(napi_env env, napi_callback_info info)
831 {
832     MediaTrace trace("AVPlayerNapi::setPlaybackRange");
833     napi_value result = nullptr;
834     napi_get_undefined(env, &result);
835     MEDIA_LOGI("JsSetPlaybackRange In");
836 
837     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
838     napi_value args[ARRAY_ARG_COUNTS_THREE] = { nullptr };
839     size_t argCount = ARRAY_ARG_COUNTS_THREE; // args[0]:startTimeMs, args[1]:endTimeMs, args[2]:SeekMode
840     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
841     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
842 
843     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
844     napi_valuetype valueType = napi_undefined;
845     int32_t startTimeMs = PLAY_RANGE_DEFAULT_VALUE;
846     int32_t endTimeMs = PLAY_RANGE_DEFAULT_VALUE;
847     int32_t mode = SEEK_PREVIOUS_SYNC;
848     if (!jsPlayer->CanSetPlayRange()) {
849         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
850             "current state is not initialized/prepared/paused/stopped/completed, unsupport setPlaybackRange operation");
851     } else if (argCount < ARRAY_ARG_COUNTS_TWO || napi_typeof(env, args[INDEX_A], &valueType) != napi_ok ||
852         valueType != napi_number || napi_typeof(env, args[INDEX_B], &valueType) != napi_ok || valueType != napi_number
853         || napi_get_value_int32(env, args[INDEX_A], &startTimeMs) != napi_ok ||
854         napi_get_value_int32(env, args[INDEX_B], &endTimeMs) != napi_ok ||
855         startTimeMs < PLAY_RANGE_DEFAULT_VALUE || endTimeMs < PLAY_RANGE_DEFAULT_VALUE) {
856         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check start or end time");
857     } else if (argCount > ARRAY_ARG_COUNTS_TWO && (napi_typeof(env, args[INDEX_C], &valueType) != napi_ok ||
858         valueType != napi_number || napi_get_value_int32(env, args[INDEX_C], &mode) != napi_ok ||
859         mode < SEEK_PREVIOUS_SYNC || mode > SEEK_MODE_CLOSEST)) {
860         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check seek mode");
861     } else {
862         promiseCtx->asyncTask = jsPlayer->EqueueSetPlayRangeTask(startTimeMs, endTimeMs, mode);
863         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetPlaybackRange EnqueueTask Out", FAKE_POINTER(jsPlayer));
864     }
865 
866     napi_value resource = nullptr;
867     napi_create_string_utf8(env, "JsSetPlaybackRange", NAPI_AUTO_LENGTH, &resource);
868     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
869         [](napi_env env, void *data) {
870             MEDIA_LOGI("Wait JsSetPlaybackRange Task Start");
871             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
872             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
873             promiseCtx->CheckTaskResult();
874             MEDIA_LOGI("Wait JsSetPlaybackRange Task End");
875         },
876         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
877     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
878     promiseCtx.release();
879     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetPlaybackRange Out", FAKE_POINTER(jsPlayer));
880     return result;
881 }
882 
EqueueSetPlayRangeTask(int32_t start,int32_t end,int32_t mode)883 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::EqueueSetPlayRangeTask(int32_t start, int32_t end, int32_t mode)
884 {
885     auto task = std::make_shared<TaskHandler<TaskRet>>([this, start, end, mode]() {
886         std::unique_lock<std::mutex> lock(taskMutex_);
887         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetPlaybackRange Task In", FAKE_POINTER(this));
888         if (player_ != nullptr) {
889             auto ret = player_->SetPlayRangeWithMode(start, end, TransferSeekMode(mode));
890             if (ret != MSERR_OK) {
891                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
892                 return TaskRet(errCode, "failed to setPlaybackRange");
893             }
894         }
895         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetPlaybackRange Task Out", FAKE_POINTER(this));
896         return TaskRet(MSERR_EXT_API9_OK, "Success");
897     });
898     (void)taskQue_->EnqueueTask(task);
899     return task;
900 }
901 
TransferSwitchMode(int32_t mode)902 PlayerSwitchMode AVPlayerNapi::TransferSwitchMode(int32_t mode)
903 {
904     MEDIA_LOGI("Seek Task TransferSeekMode, mode: %{public}d", mode);
905     PlayerSwitchMode switchMode = PlayerSwitchMode::SWITCH_CLOSEST;
906     switch (mode) {
907         case 0:
908             switchMode = PlayerSwitchMode::SWITCH_SMOOTH;
909             break;
910         case 1:
911             switchMode = PlayerSwitchMode::SWITCH_SEGMENT;
912             break;
913         default:
914             break;
915     }
916     return switchMode;
917 }
918 
JsSetSpeed(napi_env env,napi_callback_info info)919 napi_value AVPlayerNapi::JsSetSpeed(napi_env env, napi_callback_info info)
920 {
921     MediaTrace trace("AVPlayerNapi::setSpeed");
922     napi_value result = nullptr;
923     napi_get_undefined(env, &result);
924     MEDIA_LOGI("JsSetSpeed In");
925 
926     napi_value args[1] = { nullptr };
927     size_t argCount = 1; // setSpeed(speed: number)
928     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
929     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
930 
931     if (jsPlayer->IsLiveSource()) {
932         jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support speed");
933         return result;
934     }
935 
936     napi_valuetype valueType = napi_undefined;
937     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
938         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "speed mode is not number");
939         return result;
940     }
941 
942     int32_t mode = SPEED_FORWARD_1_00_X;
943     napi_status status = napi_get_value_int32(env, args[0], &mode);
944     if (status != napi_ok || mode < SPEED_FORWARD_0_75_X || mode > SPEED_FORWARD_4_00_X ||
945         (mode == SPEED_FORWARD_4_00_X && !IsSystemApp())) {
946         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
947             "invalid parameters, please check the speed mode");
948         return result;
949     }
950 
951     if (!jsPlayer->IsControllable()) {
952         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
953             "current state is not prepared/playing/paused/completed, unsupport speed operation");
954         return result;
955     }
956 
957     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, mode]() {
958         MEDIA_LOGI("0x%{public}06" PRIXPTR " Speed Task In", FAKE_POINTER(jsPlayer));
959         if (jsPlayer->player_ != nullptr) {
960             (void)jsPlayer->player_->SetPlaybackSpeed(static_cast<PlaybackRateMode>(mode));
961         }
962         MEDIA_LOGI("0x%{public}06" PRIXPTR " Speed Task Out", FAKE_POINTER(jsPlayer));
963     });
964     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetSpeed EnqueueTask In", FAKE_POINTER(jsPlayer));
965     (void)jsPlayer->taskQue_->EnqueueTask(task);
966     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetSpeed Out", FAKE_POINTER(jsPlayer));
967     return result;
968 }
969 
JsSetPlaybackRate(napi_env env,napi_callback_info info)970 napi_value AVPlayerNapi::JsSetPlaybackRate(napi_env env, napi_callback_info info)
971 {
972     MediaTrace trace("AVPlayerNapi::setRate");
973     napi_value result = nullptr;
974     napi_get_undefined(env, &result);
975     MEDIA_LOGI("JsSetRate In");
976 
977     napi_value args[1] = { nullptr };
978     size_t argCount = 1;
979     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
980     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
981 
982     if (jsPlayer->IsLiveSource()) {
983         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "The stream is live stream, not support rate");
984         return result;
985     }
986 
987     napi_valuetype valueType = napi_undefined;
988     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
989         jsPlayer->OnErrorCb(MSERR_EXT_API20_PARAM_ERROR_OUT_OF_RANGE, "rate is not number");
990         return result;
991     }
992 
993     double rate = RATE_DEFAULT_VALUE;
994     napi_status status = napi_get_value_double(env, args[0], &rate);
995     if (status != napi_ok || !jsPlayer->IsRateValid(rate)) {
996         jsPlayer->OnErrorCb(MSERR_EXT_API20_PARAM_ERROR_OUT_OF_RANGE,
997             "invalid parameters, please check the rate");
998         return result;
999     }
1000 
1001     if (!jsPlayer->IsControllable()) {
1002         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1003             "current state is not prepared/playing/paused/completed, unsupport rate operation");
1004         return result;
1005     }
1006 
1007     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, rate]() {
1008         if (jsPlayer->player_ != nullptr) {
1009             (void)jsPlayer->player_->SetPlaybackRate(static_cast<float>(rate));
1010         }
1011     });
1012     MEDIA_LOGD("0x%{public}06" PRIXPTR " JsSetRate EnqueueTask In", FAKE_POINTER(jsPlayer));
1013     if (jsPlayer->player_ != nullptr) {
1014         (void)jsPlayer->taskQue_->EnqueueTask(task);
1015     }
1016     MEDIA_LOGD("0x%{public}06" PRIXPTR " JsSetRate Out", FAKE_POINTER(jsPlayer));
1017     return result;
1018 }
1019 
JsSetVolume(napi_env env,napi_callback_info info)1020 napi_value AVPlayerNapi::JsSetVolume(napi_env env, napi_callback_info info)
1021 {
1022     MediaTrace trace("AVPlayerNapi::setVolume");
1023     napi_value result = nullptr;
1024     napi_get_undefined(env, &result);
1025     MEDIA_LOGI("JsSetVolume In");
1026 
1027     napi_value args[1] = { nullptr };
1028     size_t argCount = 1; // setVolume(vol: number)
1029     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1030     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1031 
1032     if (jsPlayer->playerCb_->isSetVolume_) {
1033         MEDIA_LOGI("SetVolume is processing, skip this task until onVolumeChangedCb");
1034     }
1035     jsPlayer->playerCb_->isSetVolume_ = true;
1036 
1037     napi_valuetype valueType = napi_undefined;
1038     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1039         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "setVolume level is not number");
1040         return result;
1041     }
1042 
1043     double volumeLevel = 1.0f;
1044     napi_status status = napi_get_value_double(env, args[0], &volumeLevel);
1045     if (status != napi_ok || volumeLevel < 0.0f || volumeLevel > 1.0f) {
1046         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, check volume level");
1047         return result;
1048     }
1049 
1050     if (!jsPlayer->IsControllable()) {
1051         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1052             "current state is not prepared/playing/paused/completed, unsupport volume operation");
1053         return result;
1054     }
1055 #ifdef SUPPORT_JSSTACK
1056     HiviewDFX::ReportXPowerJsStackSysEvent(env, "VOLUME_CHANGE", "SRC=Media");
1057 #endif
1058     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, volumeLevel]() {
1059         MEDIA_LOGD("SetVolume Task");
1060         if (jsPlayer->player_ != nullptr) {
1061             (void)jsPlayer->player_->SetVolume(volumeLevel, volumeLevel);
1062         }
1063     });
1064     (void)jsPlayer->taskQue_->EnqueueTask(task);
1065     MEDIA_LOGI("JsSetVolume Out");
1066     return result;
1067 }
1068 
JsSelectBitrate(napi_env env,napi_callback_info info)1069 napi_value AVPlayerNapi::JsSelectBitrate(napi_env env, napi_callback_info info)
1070 {
1071     MediaTrace trace("AVPlayerNapi::setBitrate");
1072     napi_value result = nullptr;
1073     napi_get_undefined(env, &result);
1074     MEDIA_LOGI("JsSelectBitrate In");
1075 
1076     napi_value args[1] = { nullptr };
1077     size_t argCount = 1; // selectBitrate(bitRate: number)
1078     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1079     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1080 
1081     napi_valuetype valueType = napi_undefined;
1082     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1083         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "selectBitrate is not number");
1084         return result;
1085     }
1086 
1087     int32_t bitrate = 0;
1088     napi_status status = napi_get_value_int32(env, args[0], &bitrate);
1089     if (status != napi_ok || bitrate < 0) {
1090         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input bitrate");
1091         return result;
1092     }
1093 
1094     if (!jsPlayer->IsControllable()) {
1095         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1096             "current state is not prepared/playing/paused/completed, unsupport select bitrate operation");
1097         return result;
1098     }
1099 
1100     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, bitrate]() {
1101         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectBitrate Task In", FAKE_POINTER(jsPlayer));
1102         if (jsPlayer->player_ != nullptr) {
1103             (void)jsPlayer->player_->SelectBitRate(static_cast<uint32_t>(bitrate));
1104         }
1105         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectBitrate Task Out", FAKE_POINTER(jsPlayer));
1106     });
1107     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectBitrate EnqueueTask In", FAKE_POINTER(jsPlayer));
1108     (void)jsPlayer->taskQue_->EnqueueTask(task);
1109     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectBitrate Out", FAKE_POINTER(jsPlayer));
1110     return result;
1111 }
1112 
AddSubSource(std::string url)1113 void AVPlayerNapi::AddSubSource(std::string url)
1114 {
1115     MEDIA_LOGI("input url is %{private}s!", url.c_str());
1116     bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
1117     bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
1118     if (isNetwork) {
1119         auto task = std::make_shared<TaskHandler<void>>([this, url]() {
1120             MEDIA_LOGI("AddSubtitleNetworkSource Task");
1121             if (player_ != nullptr) {
1122                 if (player_->AddSubSource(url) != MSERR_OK) {
1123                     OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to AddSubtitleNetworkSource");
1124                 }
1125             }
1126         });
1127         (void)taskQue_->EnqueueTask(task);
1128     } else if (isFd) {
1129         const std::string fdHead = "fd://";
1130         std::string inputFd = url.substr(fdHead.size());
1131         int32_t fd = -1;
1132         if (!StrToInt(inputFd, fd) || fd < 0) {
1133             OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1134                 "invalid parameters, The input parameter is not a fd://+numeric string");
1135             return;
1136         }
1137 
1138         auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
1139             MEDIA_LOGI("AddSubtitleFdSource Task");
1140             if (player_ != nullptr) {
1141                 if (player_->AddSubSource(fd, 0, -1) != MSERR_OK) {
1142                     OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to AddSubtitleFdSource");
1143                 }
1144             }
1145         });
1146         (void)taskQue_->EnqueueTask(task);
1147     } else {
1148         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1149             "invalid parameters, The input parameter is not fd:// or network address");
1150     }
1151 }
1152 
JsAddSubtitleUrl(napi_env env,napi_callback_info info)1153 napi_value AVPlayerNapi::JsAddSubtitleUrl(napi_env env, napi_callback_info info)
1154 {
1155     MediaTrace trace("AVPlayerNapi::addSubtitleUrl");
1156     napi_value result = nullptr;
1157     napi_get_undefined(env, &result);
1158     MEDIA_LOGI("JsAddSubtitleUrl In");
1159 
1160     napi_value args[1] = { nullptr };
1161     size_t argCount = 1; // addSubtitleUrl(url: string)
1162     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1163     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1164 
1165     napi_valuetype valueType = napi_undefined;
1166     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1167         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
1168         return result;
1169     }
1170 
1171     // get subUrl from js
1172     std::string subUrl = CommonNapi::GetStringArgument(env, args[0]);
1173     jsPlayer->AddSubSource(subUrl);
1174 
1175     MEDIA_LOGI("JsAddSubtitleUrl Out");
1176     return result;
1177 }
1178 
JsAddSubtitleAVFileDescriptor(napi_env env,napi_callback_info info)1179 napi_value AVPlayerNapi::JsAddSubtitleAVFileDescriptor(napi_env env, napi_callback_info info)
1180 {
1181     napi_value result = nullptr;
1182     napi_get_undefined(env, &result);
1183     napi_value args[3] = { nullptr };
1184     size_t argCount = 3; // url: string
1185     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1186     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1187     int32_t subtitleFd = -1;
1188     napi_status status = napi_get_value_int32(env, args[0], &subtitleFd);
1189     if (status != napi_ok) {
1190         MEDIA_LOGE("JsAddSubtitleAVFileDescriptor status != napi_ok");
1191         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1192             "invalid parameters, please check JsAddSubtitleAVFileDescriptor");
1193         return result;
1194     }
1195     int64_t offset = -1;
1196     napi_status status_offset = napi_get_value_int64(env, args[1], &offset);
1197     if (status_offset != napi_ok) {
1198         MEDIA_LOGI("JsAddSubtitleAVFileDescriptor status_offset != napi_ok");
1199         offset = 0;
1200     }
1201     int64_t length = -1;
1202     napi_status status_length = napi_get_value_int64(env, args[2], &length);
1203     if (status_length != napi_ok) {
1204         MEDIA_LOGI("JsAddSubtitleAVFileDescriptor status_length != napi_ok");
1205         length = 0;
1206     }
1207     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, subtitleFd, offset, length]() {
1208         if (jsPlayer->player_ != nullptr) {
1209             if (jsPlayer->player_->AddSubSource(subtitleFd, offset, length) != MSERR_OK) {
1210                 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to AddSubtitleAVFileDescriptor");
1211             }
1212         }
1213     });
1214     (void)jsPlayer->taskQue_->EnqueueTask(task);
1215     MEDIA_LOGI("JsAddSubtitleAVFileDescriptor Out");
1216     return result;
1217 }
1218 
SetSource(std::string url)1219 void AVPlayerNapi::SetSource(std::string url)
1220 {
1221     bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
1222     bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
1223     if (isNetwork) {
1224         EnqueueNetworkTask(url);
1225     } else if (isFd) {
1226         std::string inputFd = url.substr(sizeof("fd://") - 1);
1227         int32_t fd = -1;
1228         if (!StrToInt(inputFd, fd) || fd < 0) {
1229             OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1230                       "invalid parameters, The input parameter is not a fd://+numeric string");
1231             return;
1232         }
1233         EnqueueFdTask(fd);
1234     } else {
1235         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1236             "invalid parameters, The input parameter is not fd:// or network address");
1237     }
1238 }
1239 
EnqueueNetworkTask(const std::string url)1240 void AVPlayerNapi::EnqueueNetworkTask(const std::string url)
1241 {
1242     auto task = std::make_shared<TaskHandler<void>>([this, url]() {
1243         std::unique_lock<std::mutex> lock(taskMutex_);
1244         auto state = GetCurrentState();
1245         if (state != AVPlayerState::STATE_IDLE) {
1246             QueueOnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
1247             return;
1248         }
1249         if (player_ != nullptr) {
1250             if (player_->SetSource(url) != MSERR_OK) {
1251                 QueueOnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to SetSourceNetWork");
1252                 return;
1253             }
1254             stopWait_ = false;
1255             stateChangeCond_.wait(lock, [this]() { return stopWait_.load() || avplayerExit_; });
1256             MEDIA_LOGI("0x%{public}06" PRIXPTR " Set source network out", FAKE_POINTER(this));
1257         }
1258     });
1259     (void)taskQue_->EnqueueTask(task);
1260 }
1261 
EnqueueFdTask(const int32_t fd)1262 void AVPlayerNapi::EnqueueFdTask(const int32_t fd)
1263 {
1264     auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
1265         std::unique_lock<std::mutex> lock(taskMutex_);
1266         auto state = GetCurrentState();
1267         if (state != AVPlayerState::STATE_IDLE) {
1268             QueueOnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set source fd");
1269             return;
1270         }
1271         if (player_ != nullptr) {
1272             if (player_->SetSource(fd, 0, -1) != MSERR_OK) {
1273                 QueueOnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to SetSourceFd");
1274                 return;
1275             }
1276             stopWait_ = false;
1277             stateChangeCond_.wait(lock, [this]() { return stopWait_.load() || avplayerExit_; });
1278             MEDIA_LOGI("Set source fd out");
1279         }
1280     });
1281     (void)taskQue_->EnqueueTask(task);
1282 }
1283 
QueueOnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)1284 void AVPlayerNapi::QueueOnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
1285 {
1286     CHECK_AND_RETURN(!isReleased_.load());
1287     auto task = std::make_shared<TaskHandler<void>>([this, errorCode, errorMsg] {
1288         OnErrorCb(errorCode, errorMsg);
1289     });
1290     (void)taskQue_->EnqueueTask(task);
1291 }
1292 
JsSetUrl(napi_env env,napi_callback_info info)1293 napi_value AVPlayerNapi::JsSetUrl(napi_env env, napi_callback_info info)
1294 {
1295     MediaTrace trace("AVPlayerNapi::set url");
1296     napi_value result = nullptr;
1297     napi_get_undefined(env, &result);
1298     MEDIA_LOGD("JsSetUrl In");
1299 
1300     napi_value args[1] = { nullptr };
1301     size_t argCount = 1; // url: string
1302     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1303     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1304 
1305     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
1306         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
1307         return result;
1308     }
1309 
1310     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
1311     napi_valuetype valueType = napi_undefined;
1312     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1313         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
1314         return result;
1315     }
1316 
1317     // get url from js
1318     jsPlayer->url_ = CommonNapi::GetStringArgument(env, args[0]);
1319     MEDIA_LOGD("JsSetUrl url: %{private}s", jsPlayer->url_.c_str());
1320     jsPlayer->SetSource(jsPlayer->url_);
1321 
1322     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetUrl Out", FAKE_POINTER(jsPlayer));
1323     return result;
1324 }
1325 
JsSetStartFrameRateOptEnabled(napi_env env,napi_callback_info info)1326 napi_value AVPlayerNapi::JsSetStartFrameRateOptEnabled(napi_env env, napi_callback_info info)
1327 {
1328     MediaTrace trace("AVPlayerNapi::SetStartFrameRateOptEnabled");
1329     napi_value result = nullptr;
1330     napi_get_undefined(env, &result);
1331     MEDIA_LOGD("JsSetStartFrameRateOptEnabled");
1332 
1333     napi_value args[1] = { nullptr };
1334     size_t argCount = 1; // enable: bool
1335     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1336     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1337 
1338     napi_valuetype valueType = napi_undefined;
1339     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
1340         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "enableStartFrameRateOpt is not napi_boolean");
1341         return result;
1342     }
1343 
1344     napi_status status = napi_get_value_bool(env, args[0], &jsPlayer->enabled_);
1345     if (status != napi_ok) {
1346         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1347             "invalid parameters, please check the input enableStartFrameRateOpt");
1348         return result;
1349     }
1350 
1351     if (!IsSystemApp()) {
1352         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1353             "invalid parameters, please dont't set");
1354         return result;
1355     }
1356 
1357     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1358         MEDIA_LOGD("SetStartFrameRateOptEnabled Task");
1359         if (jsPlayer->player_ != nullptr) {
1360             (void)jsPlayer->player_->SetStartFrameRateOptEnabled(jsPlayer->enabled_);
1361         }
1362     });
1363     (void)jsPlayer->taskQue_->EnqueueTask(task);
1364     MEDIA_LOGI("0x%{public}06" PRIXPTR " SetStartFrameRateOptEnabled Out", FAKE_POINTER(jsPlayer));
1365     return result;
1366 }
1367 
1368 #ifdef SUPPORT_AVPLAYER_DRM
JsSetDecryptConfig(napi_env env,napi_callback_info info)1369 napi_value AVPlayerNapi::JsSetDecryptConfig(napi_env env, napi_callback_info info)
1370 {
1371     MediaTrace trace("AVPlayerNapi::JsSetDecryptConfig");
1372     napi_value result = nullptr;
1373     napi_get_undefined(env, &result);
1374     MEDIA_LOGI("JsSetDecryptConfig In");
1375     napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr }; // args[0]:MediaKeySession, args[1]:svp
1376     size_t argCount = 2; // args[0]:int64, args[1]:bool
1377     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1378     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1379     bool svp = 0;
1380     napi_status status = napi_get_value_bool(env, args[1], &svp);
1381     if (status != napi_ok) {
1382         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "secureVideoPath type should be boolean.");
1383         return result;
1384     }
1385     napi_value sessionObj;
1386     status = napi_coerce_to_object(env, args[0], &sessionObj);
1387     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "JsSetDecryptConfig get sessionObj failure!");
1388 
1389     napi_valuetype valueType;
1390     if (argCount < 1 || napi_typeof(env, sessionObj, &valueType) != napi_ok || valueType != napi_object) {
1391         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "mediaKeySession should be drm.MediaKeySession.");
1392         return result;
1393     }
1394     napi_value nativePointer = nullptr;
1395     std::string type = "MediaKeySessionNative";
1396     bool exist = false;
1397     status = napi_has_named_property(env, sessionObj, type.c_str(), &exist);
1398 
1399     CHECK_AND_RETURN_RET_LOG(status == napi_ok && exist, result, "can not find %{public}s property", type.c_str());
1400     CHECK_AND_RETURN_RET_LOG(napi_get_named_property(env, sessionObj, type.c_str(), &nativePointer) == napi_ok,
1401         result, "get %{public}s property fail", type.c_str());
1402 
1403     int64_t nativePointerInt;
1404     CHECK_AND_RETURN_RET_LOG(napi_get_value_int64(env, nativePointer, &nativePointerInt) == napi_ok, result,
1405         "get %{public}s property value fail", type.c_str());
1406     DrmStandard::MediaKeySessionImpl* keySessionImpl =
1407         reinterpret_cast<DrmStandard::MediaKeySessionImpl*>(nativePointerInt);
1408     if (keySessionImpl != nullptr) {
1409         sptr<DrmStandard::IMediaKeySessionService> keySessionServiceProxy =
1410             keySessionImpl->GetMediaKeySessionServiceProxy();
1411         MEDIA_LOGD("And it's count is: %{public}d", keySessionServiceProxy->GetSptrRefCount());
1412         {
1413             std::lock_guard<std::mutex> lock(jsPlayer->syncMutex_);
1414             CHECK_AND_RETURN_RET_LOG((jsPlayer->player_ != nullptr), result, "JsSetDecryptConfig player_ nullptr");
1415             (void)jsPlayer->player_->SetDecryptConfig(keySessionServiceProxy, svp);
1416         }
1417     } else {
1418         MEDIA_LOGE("SetDecryptConfig keySessionImpl is nullptr!");
1419     }
1420     return result;
1421 }
1422 #else
JsSetDecryptConfig(napi_env env,napi_callback_info info)1423 napi_value AVPlayerNapi::JsSetDecryptConfig(napi_env env, napi_callback_info info)
1424 {
1425     MEDIA_LOGI("JsSetDecryptConfig is not surpport.");
1426     (void)env;
1427     (void)info;
1428     return nullptr;
1429 }
1430 #endif
1431 
JsGetMediaKeySystemInfos(napi_env env,napi_callback_info info)1432 napi_value AVPlayerNapi::JsGetMediaKeySystemInfos(napi_env env, napi_callback_info info)
1433 {
1434     MediaTrace trace("AVPlayerNapi::JsGetMediaKeySystemInfos");
1435     napi_value result = nullptr;
1436     napi_get_undefined(env, &result);
1437     MEDIA_LOGI("JsGetMediaKeySystemInfos In");
1438 
1439     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1440     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1441     CHECK_AND_RETURN_RET_LOG(!jsPlayer->localDrmInfos_.empty(), result, "localDrmInfo is empty");
1442 
1443     uint32_t index = 0;
1444     napi_value napiMap;
1445     napi_status status = napi_create_array_with_length(env, jsPlayer->localDrmInfos_.size(), &napiMap);
1446     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "create napi array failed");
1447 
1448     for (auto item : jsPlayer->localDrmInfos_) {
1449         napi_value jsObject;
1450         napi_value jsUuid;
1451         napi_value jsPssh;
1452         napi_create_object(env, &jsObject);
1453         napi_create_string_utf8(env, item.first.c_str(), NAPI_AUTO_LENGTH, &jsUuid);
1454         napi_set_named_property(env, jsObject, "uuid", jsUuid);
1455 
1456         status = napi_create_array_with_length(env, item.second.size(), &jsPssh);
1457         CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "create napi array failed");
1458         for (uint32_t i = 0; i < item.second.size(); i++) {
1459             napi_value number = nullptr;
1460             (void)napi_create_uint32(env, item.second[i], &number);
1461             (void)napi_set_element(env, jsPssh, i, number);
1462         }
1463         napi_set_named_property(env, jsObject, "pssh", jsPssh);
1464         napi_set_element(env, napiMap, index, jsObject);
1465         index++;
1466     }
1467 
1468     return napiMap;
1469 }
1470 
JsGetPlaybackInfo(napi_env env,napi_callback_info info)1471 napi_value AVPlayerNapi::JsGetPlaybackInfo(napi_env env, napi_callback_info info)
1472 {
1473     MediaTrace trace("AVPlayerNapi::JsGetPlaybackInfo");
1474     napi_value result = nullptr;
1475     napi_get_undefined(env, &result);
1476     MEDIA_LOGI("GetPlaybackInfo In");
1477 
1478     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1479     promiseCtx->napi = AVPlayerNapi::GetJsInstance(env, info);
1480     CHECK_AND_RETURN_RET_LOG(promiseCtx->napi != nullptr, result, "failed to GetJsInstance");
1481     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
1482     // async work
1483     napi_value resource = nullptr;
1484     napi_create_string_utf8(env, "JsGetPlaybackInfo", NAPI_AUTO_LENGTH, &resource);
1485     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1486         [](napi_env env, void *data) {
1487             MEDIA_LOGI("GetPlaybackInfo Task");
1488             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1489             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1490 
1491             auto jsPlayer = promiseCtx->napi;
1492             if (jsPlayer == nullptr) {
1493                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
1494             }
1495 
1496             Format &playbackInfo = jsPlayer->playbackInfo_;
1497             if (jsPlayer->IsControllable() && jsPlayer->player_ != nullptr) {
1498                 (void)jsPlayer->player_->GetPlaybackInfo(playbackInfo);
1499             } else {
1500                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1501                     "current state unsupport get playback info");
1502             }
1503             promiseCtx->JsResult = std::make_unique<AVCodecJsResultFormat>(playbackInfo);
1504         },
1505         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1506     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1507     promiseCtx.release();
1508     MEDIA_LOGI("GetPlaybackInfo Out");
1509     return result;
1510 }
1511 
GetAVPlayStrategyFromStrategyTmp(AVPlayStrategy & strategy,const AVPlayStrategyTmp & strategyTmp)1512 void AVPlayerNapi::GetAVPlayStrategyFromStrategyTmp(AVPlayStrategy &strategy, const AVPlayStrategyTmp &strategyTmp)
1513 {
1514     strategy.preferredWidth = strategyTmp.preferredWidth;
1515     strategy.preferredHeight = strategyTmp.preferredHeight;
1516     strategy.preferredBufferDuration = strategyTmp.preferredBufferDuration;
1517     strategy.preferredHdr = strategyTmp.preferredHdr;
1518     strategy.showFirstFrameOnPrepare = strategyTmp.showFirstFrameOnPrepare;
1519     strategy.enableSuperResolution = strategyTmp.enableSuperResolution;
1520     strategy.enableCameraPostprocessing = strategyTmp.enableCameraPostprocessing;
1521     strategy.mutedMediaType = static_cast<MediaType>(strategyTmp.mutedMediaType);
1522     strategy.preferredAudioLanguage = strategyTmp.preferredAudioLanguage;
1523     strategy.preferredSubtitleLanguage = strategyTmp.preferredSubtitleLanguage;
1524     strategy.preferredBufferDurationForPlaying = strategyTmp.isSetBufferDurationForPlaying ?
1525         strategyTmp.preferredBufferDurationForPlaying : -1;
1526     strategy.thresholdForAutoQuickPlay = strategyTmp.isSetThresholdForAutoQuickPlay ?
1527         strategyTmp.thresholdForAutoQuickPlay : -1;
1528     strategy.keepDecodingOnMute = strategyTmp.keepDecodingOnMute;
1529 }
1530 
IsPalyingDurationValid(const AVPlayStrategyTmp & strategyTmp)1531 bool AVPlayerNapi::IsPalyingDurationValid(const AVPlayStrategyTmp &strategyTmp)
1532 {
1533     if ((strategyTmp.preferredBufferDuration > 0 && strategyTmp.preferredBufferDurationForPlaying > 0 &&
1534                    strategyTmp.preferredBufferDurationForPlaying > strategyTmp.preferredBufferDuration) ||
1535                    strategyTmp.preferredBufferDurationForPlaying < 0) {
1536         return false;
1537     }
1538     return true;
1539 }
1540 
IsLivingMaxDelayTimeValid(const AVPlayStrategyTmp & strategyTmp)1541 bool AVPlayerNapi::IsLivingMaxDelayTimeValid(const AVPlayStrategyTmp &strategyTmp)
1542 {
1543     if (!strategyTmp.isSetThresholdForAutoQuickPlay) {
1544         return true;
1545     }
1546     if (strategyTmp.thresholdForAutoQuickPlay < AVPlayStrategyConstant::BUFFER_DURATION_FOR_PLAYING_SECONDS ||
1547         strategyTmp.thresholdForAutoQuickPlay < strategyTmp.preferredBufferDurationForPlaying) {
1548         return false;
1549     }
1550     return true;
1551 }
1552 
IsRateValid(float rate)1553 bool AVPlayerNapi::IsRateValid(float rate)
1554 {
1555     const double minRate = 0.125f;
1556     const double maxRate = 4.0f;
1557     const double eps = 1e-15;
1558     if ((rate < minRate - eps) || (rate > maxRate + eps)) {
1559         return false;
1560     }
1561     return true;
1562 }
1563 
JsSetPlaybackStrategy(napi_env env,napi_callback_info info)1564 napi_value AVPlayerNapi::JsSetPlaybackStrategy(napi_env env, napi_callback_info info)
1565 {
1566     MediaTrace trace("AVPlayerNapi::JsSetPlaybackStrategy");
1567     napi_value result = nullptr;
1568     napi_get_undefined(env, &result);
1569     MEDIA_LOGI("JsSetPlaybackStrategy");
1570 
1571     size_t paramCountSingle = PARAM_COUNT_SINGLE;
1572     napi_value args[PARAM_COUNT_SINGLE] = { nullptr };
1573     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, paramCountSingle, args);
1574     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1575 
1576     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1577     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
1578     std::string currentState = jsPlayer->GetCurrentState();
1579     napi_valuetype valueType = napi_undefined;
1580     if (currentState != AVPlayerState::STATE_INITIALIZED && currentState != AVPlayerState::STATE_STOPPED) {
1581         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1582             "current state is not initialized / stopped, unsupport set playback strategy");
1583     } else if (napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
1584         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check input parameter");
1585     } else {
1586         AVPlayStrategyTmp strategyTmp;
1587         (void)CommonNapi::GetPlayStrategy(env, args[0], strategyTmp);
1588         if ((jsPlayer->GetJsApiVersion() < API_VERSION_17) &&
1589             (strategyTmp.mutedMediaType != MediaType::MEDIA_TYPE_AUD)) {
1590             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "only support mute media type audio now");
1591         } else if (!jsPlayer->IsPalyingDurationValid(strategyTmp)) {
1592             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER,
1593                                   "playing duration is above buffer duration or below zero");
1594         } else if (!jsPlayer->IsLivingMaxDelayTimeValid(strategyTmp)) {
1595             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER,
1596                                   "thresholdForAutoQuickPlay is invalid");
1597         } else {
1598             AVPlayStrategy strategy;
1599             jsPlayer->GetAVPlayStrategyFromStrategyTmp(strategy, strategyTmp);
1600             promiseCtx->asyncTask = jsPlayer->SetPlaybackStrategyTask(strategy);
1601             jsPlayer->mutedMediaType_ = strategy.mutedMediaType;
1602         }
1603     }
1604     napi_value resource = nullptr;
1605     napi_create_string_utf8(env, "JsSetPlaybackStrategy", NAPI_AUTO_LENGTH, &resource);
1606     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1607         [](napi_env env, void *data) {
1608             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1609             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1610             promiseCtx->CheckTaskResult();
1611         },
1612         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1613     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1614     promiseCtx.release();
1615     return result;
1616 }
1617 
JsSetMediaMuted(napi_env env,napi_callback_info info)1618 napi_value AVPlayerNapi::JsSetMediaMuted(napi_env env, napi_callback_info info)
1619 {
1620     MediaTrace trace("AVPlayerNapi::JsSetPlaybackStrategy");
1621     napi_value result = nullptr;
1622     napi_get_undefined(env, &result);
1623     MEDIA_LOGI("JsSetMediaMuted");
1624     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1625 
1626     const int32_t maxParam = 3; // config + callbackRef
1627     size_t argCount = maxParam;
1628     napi_value args[maxParam] = { nullptr };
1629     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1630     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1631 
1632     if (!jsPlayer->IsControllable()) {
1633         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1634             "current state is not prepared/playing/paused/completed, unsupport set media muted operation");
1635         return result;
1636     }
1637 
1638     int32_t mediaType = MediaType::MEDIA_TYPE_AUD;
1639     napi_get_value_int32(env, args[0], &mediaType);
1640     bool isMuted = false;
1641     napi_get_value_bool(env, args[1], &isMuted);
1642 
1643     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[maxParam - 1]);
1644     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
1645 
1646     auto curState = jsPlayer->GetCurrentState();
1647     bool canSetMute = curState == AVPlayerState::STATE_PREPARED || curState == AVPlayerState::STATE_PLAYING ||
1648                       curState == AVPlayerState::STATE_PAUSED || curState == AVPlayerState::STATE_COMPLETED;
1649     if (!canSetMute) {
1650         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1651             "current state is not initialized / stopped, unsupport set playback strategy operation");
1652     } else {
1653         promiseCtx->asyncTask = jsPlayer->SetMediaMutedTask(static_cast<MediaType>(mediaType), isMuted);
1654     }
1655     napi_value resource = nullptr;
1656     napi_create_string_utf8(env, "JsSetMediaMuted", NAPI_AUTO_LENGTH, &resource);
1657     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1658         [](napi_env env, void *data) {
1659             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1660             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1661             promiseCtx->CheckTaskResult();
1662         },
1663         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1664     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1665     promiseCtx.release();
1666     return result;
1667 }
1668 
SetMediaMutedTask(MediaType type,bool isMuted)1669 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::SetMediaMutedTask(MediaType type, bool isMuted)
1670 {
1671     auto task = std::make_shared<TaskHandler<TaskRet>>([this, type, isMuted]() {
1672         std::unique_lock<std::mutex> lock(taskMutex_);
1673         auto state = GetCurrentState();
1674         if (state == AVPlayerState::STATE_INITIALIZED || IsControllable()) {
1675             int32_t ret = player_->SetMediaMuted(type, isMuted);
1676             if (ret != MSERR_OK) {
1677                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
1678                 return TaskRet(errCode, "failed to set muted");
1679             }
1680         } else {
1681             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1682                 "current state is not stopped or initialized, unsupport prepare operation");
1683         }
1684         return TaskRet(MSERR_EXT_API9_OK, "Success");
1685     });
1686     (void)taskQue_->EnqueueTask(task);
1687     return task;
1688 }
1689 
SetPlaybackStrategyTask(AVPlayStrategy playStrategy)1690 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::SetPlaybackStrategyTask(AVPlayStrategy playStrategy)
1691 {
1692     auto task = std::make_shared<TaskHandler<TaskRet>>([this, playStrategy]() {
1693         std::unique_lock<std::mutex> lock(taskMutex_);
1694         auto state = GetCurrentState();
1695         if (state == AVPlayerState::STATE_INITIALIZED || state == AVPlayerState::STATE_STOPPED) {
1696             int32_t ret = player_->SetPlaybackStrategy(playStrategy);
1697             if (ret != MSERR_OK) {
1698                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
1699                 return TaskRet(errCode, "failed to set playback strategy");
1700             }
1701         } else {
1702             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1703                 "current state is not initialized or stopped, unsupport set playback strategy operation");
1704         }
1705         return TaskRet(MSERR_EXT_API9_OK, "Success");
1706     });
1707     (void)taskQue_->EnqueueTask(task);
1708     return task;
1709 }
1710 
JsSetSuperResolution(napi_env env,napi_callback_info info)1711 napi_value AVPlayerNapi::JsSetSuperResolution(napi_env env, napi_callback_info info)
1712 {
1713     MediaTrace trace("AVPlayerNapi::setSuperResolution");
1714     napi_value result = nullptr;
1715     napi_get_undefined(env, &result);
1716     MEDIA_LOGI("JsSetSuperResolution In");
1717 
1718     napi_value args[PARAM_COUNT_SINGLE] = { nullptr };
1719     size_t argCount = PARAM_COUNT_SINGLE; // setSuperResolution(enabled: boolean)
1720     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1721     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1722 
1723     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1724     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
1725     napi_valuetype valueType = napi_undefined;
1726 
1727     if (!jsPlayer->CanSetSuperResolution()) {
1728         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1729             "current state is not initialized/prepared/playing/paused/completed/stopped, "
1730             "unsupport set super resolution operation");
1731     } else if (argCount < PARAM_COUNT_SINGLE
1732         || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
1733         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input");
1734     } else {
1735         bool enabled = false;
1736         napi_status status = napi_get_value_bool(env, args[0], &enabled);
1737         if (status != napi_ok) {
1738             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER,
1739                 "invalid parameters, please check the input");
1740         } else {
1741             promiseCtx->asyncTask = jsPlayer->SetSuperResolutionTask(enabled);
1742         }
1743     }
1744 
1745     napi_value resource = nullptr;
1746     napi_create_string_utf8(env, "JsSetSuperResolution", NAPI_AUTO_LENGTH, &resource);
1747     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1748         [](napi_env env, void *data) {
1749             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1750             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1751             promiseCtx->CheckTaskResult();
1752         },
1753         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1754     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1755     promiseCtx.release();
1756     return result;
1757 }
1758 
SetSuperResolutionTask(bool enable)1759 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::SetSuperResolutionTask(bool enable)
1760 {
1761     auto task = std::make_shared<TaskHandler<TaskRet>>([this, enable]() {
1762         std::unique_lock<std::mutex> lock(taskMutex_);
1763         if (CanSetSuperResolution()) {
1764             int32_t ret = player_->SetSuperResolution(enable);
1765             if (ret != MSERR_OK) {
1766                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
1767                 return TaskRet(errCode, "failed to set super resolution");
1768             }
1769         } else {
1770             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1771                 "current state is not initialized/prepared/playing/paused/completed/stopped, "
1772                 "unsupport set super resolution operation");
1773         }
1774         return TaskRet(MSERR_EXT_API9_OK, "Success");
1775     });
1776     (void)taskQue_->EnqueueTask(task);
1777     return task;
1778 }
1779 
JsSetVideoWindowSize(napi_env env,napi_callback_info info)1780 napi_value AVPlayerNapi::JsSetVideoWindowSize(napi_env env, napi_callback_info info)
1781 {
1782     MediaTrace trace("AVPlayerNapi::setVideoWindowSize");
1783     napi_value result = nullptr;
1784     napi_get_undefined(env, &result);
1785     MEDIA_LOGI("JsSetVideoWindowSize In");
1786 
1787     napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr };
1788     size_t argCount = ARRAY_ARG_COUNTS_TWO; // setVideoWindowSize(width: number, height: number)
1789     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1790     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1791 
1792     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1793     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
1794     napi_valuetype valueType = napi_undefined;
1795 
1796     if (!jsPlayer->CanSetSuperResolution()) {
1797         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1798             "current state is not initialized/prepared/playing/paused/completed/stopped, "
1799             "unsupport set video window size");
1800     } else if (argCount < ARRAY_ARG_COUNTS_TWO ||
1801                 napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number ||
1802                 napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
1803         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input");
1804     } else {
1805         int32_t width = 0;
1806         int32_t height = 0;
1807         napi_status status1 = napi_get_value_int32(env, args[0], &width);
1808         napi_status status2 = napi_get_value_int32(env, args[1], &height);
1809         if (status1 != napi_ok || status2 != napi_ok) {
1810             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER,
1811                 "invalid parameters, please check the input");
1812         } else {
1813             promiseCtx->asyncTask = jsPlayer->SetVideoWindowSizeTask(width, height);
1814         }
1815     }
1816 
1817     napi_value resource = nullptr;
1818     napi_create_string_utf8(env, "JsSetVideoWindowSize", NAPI_AUTO_LENGTH, &resource);
1819     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1820         [](napi_env env, void *data) {
1821             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1822             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1823             promiseCtx->CheckTaskResult();
1824         },
1825         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1826     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1827     promiseCtx.release();
1828     return result;
1829 }
1830 
SetVideoWindowSizeTask(int32_t width,int32_t height)1831 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::SetVideoWindowSizeTask(int32_t width, int32_t height)
1832 {
1833     auto task = std::make_shared<TaskHandler<TaskRet>>([this, width, height]() {
1834         std::unique_lock<std::mutex> lock(taskMutex_);
1835         auto state = GetCurrentState();
1836         if (CanSetSuperResolution()) {
1837             int32_t ret = player_->SetVideoWindowSize(width, height);
1838             if (ret != MSERR_OK) {
1839                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
1840                 return TaskRet(errCode, "failed to set super resolution");
1841             }
1842         } else {
1843             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1844                 "current state is not initialized/prepared/playing/paused/completed/stopped, "
1845                 "unsupport set super resolution operation");
1846         }
1847         return TaskRet(MSERR_EXT_API9_OK, "Success");
1848     });
1849     (void)taskQue_->EnqueueTask(task);
1850     return task;
1851 }
1852 
JsEnableCameraPostprocessing(napi_env env,napi_callback_info info)1853 napi_value AVPlayerNapi::JsEnableCameraPostprocessing(napi_env env, napi_callback_info info)
1854 {
1855     MediaTrace trace("AVPlayerNapi::enableCameraPostprocessing");
1856     napi_value result = nullptr;
1857     napi_get_undefined(env, &result);
1858     MEDIA_LOGD("JsEnableCameraPostprocessing In");
1859 
1860     napi_value args[PARAM_COUNT_SINGLE] = { nullptr };
1861     size_t argCount = PARAM_COUNT_SINGLE; // enableCameraPostprocessing(enabled: boolean)
1862     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1863     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1864 
1865     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1866     CHECK_AND_RETURN_RET_LOG(promiseCtx != nullptr, result, "promiseCtx is null");
1867     promiseCtx->deferred = CommonNapi::CreatePromise(env, nullptr, result);
1868 
1869     if (!IsSystemApp()) {
1870         promiseCtx->SignError(MSERR_EXT_API9_PERMISSION_DENIED, "systemapi permission denied");
1871     }
1872     if (!jsPlayer->CanCameraPostprocessing()) {
1873         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1874             "current state is not initialized, unsupport enable cameraPostProcessor");
1875     } else {
1876         promiseCtx->asyncTask = jsPlayer->EnableCameraPostprocessingTask();
1877     }
1878 
1879     napi_value resource = nullptr;
1880     napi_create_string_utf8(env, "JsEnableCameraPostprocessing", NAPI_AUTO_LENGTH, &resource);
1881     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1882         [](napi_env env, void *data) {
1883             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1884             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1885             promiseCtx->CheckTaskResult();
1886         },
1887         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1888     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1889     promiseCtx.release();
1890     return result;
1891 }
1892 
EnableCameraPostprocessingTask()1893 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::EnableCameraPostprocessingTask()
1894 {
1895     auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
1896         std::unique_lock<std::mutex> lock(taskMutex_);
1897         if (CanCameraPostprocessing()) {
1898             int32_t ret = player_->EnableCameraPostprocessing();
1899             if (ret != MSERR_OK) {
1900                 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
1901                 return TaskRet(errCode, "failed to enable cameraPostProcessor");
1902             }
1903         } else {
1904             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1905                 "current state is not initialized, unsupport enable cameraPostProcessor");
1906         }
1907         return TaskRet(MSERR_EXT_API9_OK, "Success");
1908     });
1909     (void)taskQue_->EnqueueTask(task);
1910     return task;
1911 }
1912 
JsGetUrl(napi_env env,napi_callback_info info)1913 napi_value AVPlayerNapi::JsGetUrl(napi_env env, napi_callback_info info)
1914 {
1915     MediaTrace trace("AVPlayerNapi::get url");
1916     napi_value result = nullptr;
1917     napi_get_undefined(env, &result);
1918     MEDIA_LOGD("JsGetUrl In");
1919 
1920     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1921     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1922 
1923     napi_value value = nullptr;
1924     (void)napi_create_string_utf8(env, jsPlayer->url_.c_str(), NAPI_AUTO_LENGTH, &value);
1925 
1926     MEDIA_LOGD("JsGetUrl Out Current Url: %{private}s", jsPlayer->url_.c_str());
1927     return value;
1928 }
1929 
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)1930 napi_value AVPlayerNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
1931 {
1932     MediaTrace trace("AVPlayerNapi::set fd");
1933     napi_value result = nullptr;
1934     napi_get_undefined(env, &result);
1935     MEDIA_LOGI("JsSetAVFileDescriptor In");
1936 
1937     napi_value args[1] = { nullptr };
1938     size_t argCount = 1; // url: string
1939     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1940     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1941 
1942     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
1943         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set fd");
1944         return result;
1945     }
1946 
1947     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
1948     napi_valuetype valueType = napi_undefined;
1949     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
1950         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAVFileDescriptor is not napi_object");
1951         return result;
1952     }
1953 
1954     if (!CommonNapi::GetFdArgument(env, args[0], jsPlayer->fileDescriptor_)) {
1955         MEDIA_LOGE("get fileDescriptor argument failed!");
1956         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1957             "invalid parameters, please check the input parameters(fileDescriptor)");
1958         return result;
1959     }
1960 
1961     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1962         MEDIA_LOGI("SetAVFileDescriptor Task");
1963         if (jsPlayer->player_ != nullptr) {
1964             auto playerFd = jsPlayer->fileDescriptor_;
1965             MEDIA_LOGI("JsSetAVFileDescriptor fd: %{public}d, offset: %{public}"
1966                 PRId64 ", size: %{public}" PRId64, playerFd.fd, playerFd.offset, playerFd.length);
1967             if (jsPlayer->player_->SetSource(playerFd.fd, playerFd.offset, playerFd.length) != MSERR_OK) {
1968                 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource FileDescriptor failed");
1969             }
1970         }
1971     });
1972     (void)jsPlayer->taskQue_->EnqueueTask(task);
1973 
1974     MEDIA_LOGI("JsSetAVFileDescriptor Out");
1975     return result;
1976 }
1977 
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)1978 napi_value AVPlayerNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
1979 {
1980     MediaTrace trace("AVPlayerNapi::get fd");
1981     napi_value result = nullptr;
1982     napi_get_undefined(env, &result);
1983     MEDIA_LOGI("JsGetAVFileDescriptor In");
1984 
1985     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1986     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1987 
1988     napi_value value = nullptr;
1989     (void)napi_create_object(env, &value);
1990     (void)CommonNapi::AddNumberPropInt32(env, value, "fd", jsPlayer->fileDescriptor_.fd);
1991     (void)CommonNapi::AddNumberPropInt64(env, value, "offset", jsPlayer->fileDescriptor_.offset);
1992     (void)CommonNapi::AddNumberPropInt64(env, value, "length", jsPlayer->fileDescriptor_.length);
1993 
1994     MEDIA_LOGI("JsGetAVFileDescriptor Out");
1995     return value;
1996 }
1997 
JsSetMediaSource(napi_env env,napi_callback_info info)1998 napi_value AVPlayerNapi::JsSetMediaSource(napi_env env, napi_callback_info info)
1999 {
2000     MediaTrace trace("AVPlayerNapi::JsSetMediaSource");
2001     napi_value result = nullptr;
2002     napi_get_undefined(env, &result);
2003     napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr };
2004     size_t argCount = 2;
2005     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2006     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2007 
2008     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
2009         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set mediaSource");
2010         return result;
2011     }
2012     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
2013     napi_valuetype valueType = napi_undefined;
2014     if (argCount < MIN_ARG_COUNTS || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
2015         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "src type should be MediaSource.");
2016         return result;
2017     }
2018     if (argCount > MAX_ARG_COUNTS) { // api allow one param
2019         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check");
2020         return result;
2021     }
2022     std::shared_ptr<AVMediaSourceTmp> srcTmp = MediaSourceNapi::GetMediaSource(env, args[0]);
2023     CHECK_AND_RETURN_RET_LOG(srcTmp != nullptr, result, "get GetMediaSource argument failed!");
2024 
2025     std::shared_ptr<AVMediaSource> mediaSource = GetAVMediaSource(env, args[0], srcTmp);
2026     CHECK_AND_RETURN_RET_LOG(mediaSource != nullptr, result, "create mediaSource failed!");
2027     jsPlayer->AddMediaStreamToAVMediaSource(srcTmp, mediaSource);
2028 
2029     struct AVPlayStrategyTmp strategyTmp;
2030     struct AVPlayStrategy strategy;
2031     if (!CommonNapi::GetPlayStrategy(env, args[1], strategyTmp)) {
2032         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "strategy type should be PlaybackStrategy.");
2033         return result;
2034     } else if (!jsPlayer->IsPalyingDurationValid(strategyTmp)) {
2035         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "playing duration is invalid");
2036         return result;
2037     } else if (!jsPlayer->IsLivingMaxDelayTimeValid(strategyTmp)) {
2038         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "thresholdForAutoQuickPlay is invalid");
2039         return result;
2040     }
2041     jsPlayer->GetAVPlayStrategyFromStrategyTmp(strategy, strategyTmp);
2042     if (jsPlayer->GetJsApiVersion() < API_VERSION_17) {
2043         strategy.mutedMediaType = MediaType::MEDIA_TYPE_MAX_COUNT;
2044     }
2045     jsPlayer->EnqueueMediaSourceTask(jsPlayer, mediaSource, strategy);
2046     return result;
2047 }
2048 
GetAVMediaSource(napi_env env,napi_value value,std::shared_ptr<AVMediaSourceTmp> & srcTmp)2049 std::shared_ptr<AVMediaSource> AVPlayerNapi::GetAVMediaSource(napi_env env, napi_value value,
2050     std::shared_ptr<AVMediaSourceTmp> &srcTmp)
2051 {
2052     std::shared_ptr<AVMediaSource> mediaSource = std::make_shared<AVMediaSource>(srcTmp->url, srcTmp->header);
2053     CHECK_AND_RETURN_RET_LOG(mediaSource != nullptr, nullptr, "create mediaSource failed!");
2054     mediaSource->SetMimeType(srcTmp->GetMimeType());
2055     mediaSource->mediaSourceLoaderCb_ = MediaSourceNapi::GetSourceLoader(env, value);
2056     if (mediaSource->mediaSourceLoaderCb_ == nullptr) {
2057         MEDIA_LOGI("mediaSourceLoaderCb_ nullptr");
2058     }
2059     return mediaSource;
2060 }
2061 
EnqueueMediaSourceTask(AVPlayerNapi * jsPlayer,const std::shared_ptr<AVMediaSource> & mediaSource,const struct AVPlayStrategy & strategy)2062 void AVPlayerNapi::EnqueueMediaSourceTask(AVPlayerNapi *jsPlayer, const std::shared_ptr<AVMediaSource> &mediaSource,
2063                                           const struct AVPlayStrategy &strategy)
2064 {
2065     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, mediaSource, strategy]() {
2066         if (jsPlayer->player_ != nullptr) {
2067             (void)jsPlayer->player_->SetMediaSource(mediaSource, strategy);
2068         }
2069     });
2070     (void)jsPlayer->taskQue_->EnqueueTask(task);
2071 }
2072 
JsSetDataSrc(napi_env env,napi_callback_info info)2073 napi_value AVPlayerNapi::JsSetDataSrc(napi_env env, napi_callback_info info)
2074 {
2075     MediaTrace trace("AVPlayerNapi::set dataSrc");
2076     napi_value result = nullptr;
2077     napi_get_undefined(env, &result);
2078     MEDIA_LOGI("JsSetDataSrc In");
2079 
2080     napi_value args[1] = { nullptr };
2081     size_t argCount = 1;
2082     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2083     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2084 
2085     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
2086         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set dataSrc");
2087         return result;
2088     }
2089     jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
2090 
2091     napi_valuetype valueType = napi_undefined;
2092     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
2093         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "args[0] is not napi_object");
2094         return result;
2095     }
2096     (void)CommonNapi::GetPropertyInt64(env, args[0], "fileSize", jsPlayer->dataSrcDescriptor_.fileSize);
2097     if (jsPlayer->dataSrcDescriptor_.fileSize < -1 || jsPlayer->dataSrcDescriptor_.fileSize == 0) {
2098         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check parameter fileSize");
2099         return result;
2100     }
2101     MEDIA_LOGD("Recvive filesize is %{public}" PRId64 "", jsPlayer->dataSrcDescriptor_.fileSize);
2102     jsPlayer->dataSrcCb_ = std::make_shared<MediaDataSourceCallback>(env, jsPlayer->dataSrcDescriptor_.fileSize);
2103 
2104     napi_value callback = nullptr;
2105     napi_ref ref = nullptr;
2106     napi_get_named_property(env, args[0], "callback", &callback);
2107     jsPlayer->dataSrcDescriptor_.callback = callback;
2108     napi_status status = napi_create_reference(env, callback, 1, &ref);
2109     CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
2110     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
2111     jsPlayer->dataSrcCb_->SaveCallbackReference(READAT_CALLBACK_NAME, autoRef);
2112     jsPlayer->SetDataSource(jsPlayer);
2113     MEDIA_LOGI("JsSetDataSrc Out");
2114     return result;
2115 }
2116 
SetDataSource(AVPlayerNapi * jsPlayer)2117 void AVPlayerNapi::SetDataSource(AVPlayerNapi *jsPlayer)
2118 {
2119     MEDIA_LOGI("SetDataSource while setStateChange_ %{public}d", jsPlayer->hasSetStateChangeCb_);
2120     if (jsPlayer->hasSetStateChangeCb_) {
2121         if (jsPlayer->player_ != nullptr) {
2122             if (jsPlayer->player_->SetSource(jsPlayer->dataSrcCb_) != MSERR_OK) {
2123                 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource DataSrc failed");
2124             } else {
2125                 jsPlayer->state_ = PlayerStates::PLAYER_INITIALIZED;
2126             }
2127             if (jsPlayer->dataSrcDescriptor_.fileSize == -1) {
2128                 jsPlayer->isLiveStream_ = true;
2129             }
2130         }
2131         return;
2132     }
2133 
2134     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
2135         MEDIA_LOGI("SetDataSrc Task");
2136         if (jsPlayer->player_ != nullptr) {
2137             if (jsPlayer->player_->SetSource(jsPlayer->dataSrcCb_) != MSERR_OK) {
2138                 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource DataSrc failed");
2139             }
2140             if (jsPlayer->dataSrcDescriptor_.fileSize == -1) {
2141                 jsPlayer->isLiveStream_ = true;
2142             }
2143         }
2144     });
2145     (void)jsPlayer->taskQue_->EnqueueTask(task);
2146 }
2147 
JsGetDataSrc(napi_env env,napi_callback_info info)2148 napi_value AVPlayerNapi::JsGetDataSrc(napi_env env, napi_callback_info info)
2149 {
2150     MediaTrace trace("AVPlayerNapi::get dataSrc");
2151     napi_value result = nullptr;
2152     napi_get_undefined(env, &result);
2153     MEDIA_LOGI("JsGetDataSrc In");
2154 
2155     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2156     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2157     CHECK_AND_RETURN_RET_LOG(jsPlayer->dataSrcCb_ != nullptr, result, "failed to check dataSrcCb_");
2158 
2159     napi_value value = nullptr;
2160     int64_t fileSize;
2161     napi_value callback = nullptr;
2162     (void)napi_create_object(env, &value);
2163     (void)jsPlayer->dataSrcCb_->GetSize(fileSize);
2164     (void)CommonNapi::AddNumberPropInt64(env, value, "fileSize", fileSize);
2165     int32_t ret = jsPlayer->dataSrcCb_->GetCallback(READAT_CALLBACK_NAME, &callback);
2166     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, result, "failed to GetCallback");
2167     (void)MediaDataSourceCallback::AddNapiValueProp(env, value, "callback", callback);
2168 
2169     MEDIA_LOGI("JsGetDataSrc Out");
2170     return value;
2171 }
2172 
2173 #ifdef SUPPORT_VIDEO
SetSurface(const std::string & surfaceStr)2174 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
2175 {
2176     MEDIA_LOGI("get surface, surfaceStr = %{public}s", surfaceStr.c_str());
2177     uint64_t surfaceId = 0;
2178     if (surfaceStr.empty() || surfaceStr[0] < '0' || surfaceStr[0] > '9') {
2179         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2180             "Please obtain the surface from XComponentController.getXComponentSurfaceId");
2181         return;
2182     }
2183     if (!StrToULL(surfaceStr, surfaceId)) {
2184         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2185             "invalid parameters, failed to obtain surfaceId");
2186         return;
2187     }
2188     MEDIA_LOGI("get surface, surfaceId = (%{public}" PRIu64 ")", surfaceId);
2189 
2190     auto surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
2191     if (surface == nullptr) {
2192         OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SurfaceUtils cannot convert ID to Surface");
2193         return;
2194     }
2195 
2196     auto task = std::make_shared<TaskHandler<void>>([this, surface]() {
2197         MEDIA_LOGI("0x%{public}06" PRIXPTR " SetSurface Task", FAKE_POINTER(this));
2198         if (player_ != nullptr) {
2199             (void)player_->SetVideoSurface(surface);
2200         }
2201     });
2202     (void)taskQue_->EnqueueTask(task);
2203 }
2204 #else
SetSurface(const std::string & surfaceStr)2205 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
2206 {
2207     (void)surfaceStr;
2208     OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The music player does not need to support (Surface)");
2209 }
2210 #endif
2211 
JsSetSurfaceID(napi_env env,napi_callback_info info)2212 napi_value AVPlayerNapi::JsSetSurfaceID(napi_env env, napi_callback_info info)
2213 {
2214     MediaTrace trace("AVPlayerNapi::set surface");
2215     napi_value result = nullptr;
2216     napi_get_undefined(env, &result);
2217     MEDIA_LOGD("JsSetSurfaceID In");
2218 
2219     napi_value args[1] = { nullptr };
2220     size_t argCount = 1; // surfaceId?: string
2221     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2222     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2223 
2224     napi_valuetype valueType = napi_undefined;
2225     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
2226         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "the attribute(SurfaceID) input is not string");
2227         return result;
2228     }
2229 
2230     std::string curState = jsPlayer->GetCurrentState();
2231     bool setSurfaceFirst = curState == AVPlayerState::STATE_INITIALIZED;
2232     bool switchSurface = curState == AVPlayerState::STATE_PREPARED ||
2233         curState == AVPlayerState::STATE_PLAYING ||
2234         curState == AVPlayerState::STATE_PAUSED ||
2235         curState == AVPlayerState::STATE_STOPPED ||
2236         curState == AVPlayerState::STATE_COMPLETED;
2237 
2238     if (setSurfaceFirst) {
2239         MEDIA_LOGI("JsSetSurfaceID set surface first in %{public}s state", curState.c_str());
2240     } else if (switchSurface) {
2241         MEDIA_LOGI("JsSetSurfaceID switch surface in %{public}s state", curState.c_str());
2242         std::string oldSurface = jsPlayer->surface_;
2243         if (oldSurface.empty() && !jsPlayer->isForceLoadVideo_ &&
2244             jsPlayer->mutedMediaType_ != OHOS::Media::MediaType::MEDIA_TYPE_VID) {
2245             jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2246                 "switch surface with no old surface");
2247             return result;
2248         }
2249     } else {
2250         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2251             "the attribute(SurfaceID) can only be set in the initialized state");
2252         return result;
2253     }
2254 
2255     // get url from js
2256     jsPlayer->surface_ = CommonNapi::GetStringArgument(env, args[0]);
2257     jsPlayer->SetSurface(jsPlayer->surface_);
2258     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetSurfaceID Out", FAKE_POINTER(jsPlayer));
2259     return result;
2260 }
2261 
JsGetSurfaceID(napi_env env,napi_callback_info info)2262 napi_value AVPlayerNapi::JsGetSurfaceID(napi_env env, napi_callback_info info)
2263 {
2264     MediaTrace trace("AVPlayerNapi::get surface");
2265     napi_value result = nullptr;
2266     napi_get_undefined(env, &result);
2267     MEDIA_LOGD("JsGetSurfaceID In");
2268 
2269     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2270     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2271 
2272     napi_value value = nullptr;
2273     (void)napi_create_string_utf8(env, jsPlayer->surface_.c_str(), NAPI_AUTO_LENGTH, &value);
2274 
2275     MEDIA_LOGI("JsGetSurfaceID Out Current SurfaceID: %{public}s", jsPlayer->surface_.c_str());
2276     return value;
2277 }
2278 
JsSetLoop(napi_env env,napi_callback_info info)2279 napi_value AVPlayerNapi::JsSetLoop(napi_env env, napi_callback_info info)
2280 {
2281     MediaTrace trace("AVPlayerNapi::set loop");
2282     napi_value result = nullptr;
2283     napi_get_undefined(env, &result);
2284     MEDIA_LOGI("JsSetLoop In");
2285 
2286     napi_value args[1] = { nullptr };
2287     size_t argCount = 1; // loop: boolenan
2288     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2289     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2290 
2291     if (jsPlayer->IsLiveSource()) {
2292         jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support loop");
2293         return result;
2294     }
2295 
2296     if (!jsPlayer->IsControllable()) {
2297         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2298             "current state is not prepared/playing/paused/completed, unsupport loop operation");
2299         return result;
2300     }
2301 
2302     napi_valuetype valueType = napi_undefined;
2303     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
2304         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetLoop is not napi_boolean");
2305         return result;
2306     }
2307 
2308     napi_status status = napi_get_value_bool(env, args[0], &jsPlayer->loop_);
2309     if (status != napi_ok) {
2310         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2311             "invalid parameters, please check the input loop");
2312         return result;
2313     }
2314 
2315     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
2316         MEDIA_LOGD("SetLooping Task");
2317         if (jsPlayer->player_ != nullptr) {
2318             (void)jsPlayer->player_->SetLooping(jsPlayer->loop_);
2319         }
2320     });
2321     (void)jsPlayer->taskQue_->EnqueueTask(task);
2322     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetLoop Out", FAKE_POINTER(jsPlayer));
2323     return result;
2324 }
2325 
JsGetLoop(napi_env env,napi_callback_info info)2326 napi_value AVPlayerNapi::JsGetLoop(napi_env env, napi_callback_info info)
2327 {
2328     MediaTrace trace("AVPlayerNapi::get loop");
2329     napi_value result = nullptr;
2330     napi_get_undefined(env, &result);
2331     MEDIA_LOGI("JsGetLoop In");
2332 
2333     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2334     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2335 
2336     napi_value value = nullptr;
2337     (void)napi_get_boolean(env, jsPlayer->loop_, &value);
2338     MEDIA_LOGI("JsGetLoop Out Current Loop: %{public}d", jsPlayer->loop_);
2339     return value;
2340 }
2341 
JsSetVideoScaleType(napi_env env,napi_callback_info info)2342 napi_value AVPlayerNapi::JsSetVideoScaleType(napi_env env, napi_callback_info info)
2343 {
2344     MediaTrace trace("AVPlayerNapi::set videoScaleType");
2345     napi_value result = nullptr;
2346     napi_get_undefined(env, &result);
2347     MEDIA_LOGI("JsSetVideoScaleType In");
2348 
2349     napi_value args[1] = { nullptr };
2350     size_t argCount = 1;
2351     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2352     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2353 
2354     if (!jsPlayer->IsControllable()) {
2355         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2356             "current state is not prepared/playing/paused/completed, unsupport video scale operation");
2357         return result;
2358     }
2359 
2360     napi_valuetype valueType = napi_undefined;
2361     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
2362         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetVideoScaleType is not napi_number");
2363         return result;
2364     }
2365 
2366     int32_t videoScaleType = 0;
2367     napi_status status = napi_get_value_int32(env, args[0], &videoScaleType);
2368     if (status != napi_ok || videoScaleType < static_cast<int32_t>(Plugins::VideoScaleType::VIDEO_SCALE_TYPE_FIT)
2369         || videoScaleType > static_cast<int32_t>(Plugins::VideoScaleType::VIDEO_SCALE_TYPE_SCALED_ASPECT)) {
2370         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input scale type");
2371         return result;
2372     }
2373     jsPlayer->videoScaleType_ = videoScaleType;
2374 
2375     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, videoScaleType]() {
2376         MEDIA_LOGI("SetVideoScaleType Task");
2377         if (jsPlayer->player_ != nullptr) {
2378             Format format;
2379             (void)format.PutIntValue(PlayerKeys::VIDEO_SCALE_TYPE, videoScaleType);
2380             (void)jsPlayer->player_->SetParameter(format);
2381         }
2382     });
2383     (void)jsPlayer->taskQue_->EnqueueTask(task);
2384     MEDIA_LOGI("JsSetVideoScaleType Out");
2385     return result;
2386 }
2387 
JsGetVideoScaleType(napi_env env,napi_callback_info info)2388 napi_value AVPlayerNapi::JsGetVideoScaleType(napi_env env, napi_callback_info info)
2389 {
2390     MediaTrace trace("AVPlayerNapi::get videoScaleType");
2391     napi_value result = nullptr;
2392     napi_get_undefined(env, &result);
2393     MEDIA_LOGI("JsGetVideoScaleType In");
2394 
2395     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2396     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2397 
2398     napi_value value = nullptr;
2399     (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->videoScaleType_), &value);
2400     MEDIA_LOGI("JsGetVideoScaleType Out Current VideoScale: %{public}d", jsPlayer->videoScaleType_);
2401     return value;
2402 }
2403 
JsSetAudioInterruptMode(napi_env env,napi_callback_info info)2404 napi_value AVPlayerNapi::JsSetAudioInterruptMode(napi_env env, napi_callback_info info)
2405 {
2406     MediaTrace trace("AVPlayerNapi::set audioInterruptMode");
2407     napi_value result = nullptr;
2408     napi_get_undefined(env, &result);
2409     MEDIA_LOGI("JsSetAudioInterruptMode In");
2410 
2411     napi_value args[1] = { nullptr };
2412     size_t argCount = 1;
2413     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2414     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2415 
2416     if (!jsPlayer->IsControllable()) {
2417         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2418             "current state is not prepared/playing/paused/completed, unsupport audio interrupt operation");
2419         return result;
2420     }
2421 
2422     napi_valuetype valueType = napi_undefined;
2423     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
2424         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAudioInterruptMode is not napi_number");
2425         return result;
2426     }
2427 
2428     int32_t interruptMode = 0;
2429     napi_status status = napi_get_value_int32(env, args[0], &interruptMode);
2430     if (status != napi_ok ||
2431         interruptMode < AudioStandard::InterruptMode::SHARE_MODE ||
2432         interruptMode > AudioStandard::InterruptMode::INDEPENDENT_MODE) {
2433         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2434             "invalid parameters, please check the input interrupt Mode");
2435         return result;
2436     }
2437     jsPlayer->interruptMode_ = static_cast<AudioStandard::InterruptMode>(interruptMode);
2438 
2439     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
2440         MEDIA_LOGI("SetAudioInterruptMode Task");
2441         if (jsPlayer->player_ != nullptr) {
2442             Format format;
2443             (void)format.PutIntValue(PlayerKeys::AUDIO_INTERRUPT_MODE, jsPlayer->interruptMode_);
2444             (void)jsPlayer->player_->SetParameter(format);
2445         }
2446     });
2447     (void)jsPlayer->taskQue_->EnqueueTask(task);
2448     MEDIA_LOGI("JsSetAudioInterruptMode Out");
2449     return result;
2450 }
2451 
JsGetAudioInterruptMode(napi_env env,napi_callback_info info)2452 napi_value AVPlayerNapi::JsGetAudioInterruptMode(napi_env env, napi_callback_info info)
2453 {
2454     MediaTrace trace("AVPlayerNapi::get audioInterruptMode");
2455     napi_value result = nullptr;
2456     napi_get_undefined(env, &result);
2457     MEDIA_LOGI("JsGetAudioInterruptMode In");
2458 
2459     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2460     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2461 
2462     napi_value value = nullptr;
2463     (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->interruptMode_), &value);
2464     MEDIA_LOGI("JsGetAudioInterruptMode Out");
2465     return value;
2466 }
2467 
JsSetAudioEffectMode(napi_env env,napi_callback_info info)2468 napi_value AVPlayerNapi::JsSetAudioEffectMode(napi_env env, napi_callback_info info)
2469 {
2470     MediaTrace trace("AVPlayerNapi::JsSetAudioEffectMode");
2471     MEDIA_LOGI("JsSetAudioEffectMode In");
2472     napi_value result = nullptr;
2473     napi_get_undefined(env, &result);
2474 
2475     size_t argCount = 1; // 1param audioEffectMode
2476     napi_value args[1] = { nullptr };
2477     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2478     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2479 
2480     if (!jsPlayer->IsControllable()) {
2481         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2482             "current state is not prepared/playing/paused/completed, unsupport audio effect mode operation");
2483         return result;
2484     }
2485 
2486     napi_valuetype valueType = napi_undefined;
2487     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
2488         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "audioEffectMode is not number");
2489         return result;
2490     }
2491 
2492     int32_t effectMode = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
2493     napi_status status = napi_get_value_int32(env, args[0], &effectMode);
2494     if (status != napi_ok || effectMode > OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT ||
2495         effectMode < OHOS::AudioStandard::AudioEffectMode::EFFECT_NONE) {
2496         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2497             "invalid audioEffectMode, please check the input audio effect Mode");
2498         return result;
2499     }
2500 
2501     if (jsPlayer->audioEffectMode_ == effectMode) {
2502         MEDIA_LOGI("Same effectMode parameter");
2503         return result;
2504     }
2505 
2506     jsPlayer->audioEffectMode_ = effectMode;
2507 
2508     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, effectMode]() {
2509         MEDIA_LOGI("JsSetAudioEffectMode Task in");
2510         if (jsPlayer->player_ != nullptr) {
2511             Format format;
2512             (void)format.PutIntValue(PlayerKeys::AUDIO_EFFECT_MODE, effectMode);
2513             (void)jsPlayer->player_->SetParameter(format);
2514         }
2515         MEDIA_LOGI("JsSetAudioEffectMode Task out");
2516     });
2517     (void)jsPlayer->taskQue_->EnqueueTask(task);
2518     MEDIA_LOGI("JsSetAudioEffectMode Out");
2519     return result;
2520 }
2521 
JsGetAudioEffectMode(napi_env env,napi_callback_info info)2522 napi_value AVPlayerNapi::JsGetAudioEffectMode(napi_env env, napi_callback_info info)
2523 {
2524     MediaTrace trace("AVPlayerNapi::JsGetAudioEffectMode");
2525     MEDIA_LOGI("JsGetAudioEffectMode In");
2526     napi_value result = nullptr;
2527     napi_get_undefined(env, &result);
2528 
2529     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2530     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2531 
2532     napi_value value = nullptr;
2533     (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->audioEffectMode_), &value);
2534     MEDIA_LOGI("JsGetAudioEffectMode Out");
2535     return value;
2536 }
2537 
JsHandleParameter(napi_env env,napi_value args,AVPlayerNapi * jsPlayer)2538 bool AVPlayerNapi::JsHandleParameter(napi_env env, napi_value args, AVPlayerNapi *jsPlayer)
2539 {
2540     int32_t content = CONTENT_TYPE_UNKNOWN;
2541     int32_t usage = -1;
2542     int32_t rendererFlags = -1;
2543     int32_t volumeMode = -1;
2544     (void)CommonNapi::GetPropertyInt32(env, args, "content", content);
2545     (void)CommonNapi::GetPropertyInt32(env, args, "usage", usage);
2546     (void)CommonNapi::GetPropertyInt32(env, args, "rendererFlags", rendererFlags);
2547     (void)CommonNapi::GetPropertyInt32(env, args, "volumeMode", volumeMode);
2548     MEDIA_LOGI("content = %{public}d, usage = %{public}d, rendererFlags = %{public}d, volumeMode = %{public}d",
2549         content, usage, rendererFlags, volumeMode);
2550     std::vector<int32_t> contents = {
2551         CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_SPEECH,
2552         CONTENT_TYPE_MUSIC, CONTENT_TYPE_MOVIE,
2553         CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_RINGTONE
2554     };
2555     std::vector<int32_t> usages = {
2556         STREAM_USAGE_UNKNOWN, STREAM_USAGE_MEDIA,
2557         STREAM_USAGE_MUSIC, STREAM_USAGE_VOICE_COMMUNICATION,
2558         STREAM_USAGE_VOICE_ASSISTANT, STREAM_USAGE_ALARM,
2559         STREAM_USAGE_VOICE_MESSAGE, STREAM_USAGE_NOTIFICATION_RINGTONE,
2560         STREAM_USAGE_RINGTONE, STREAM_USAGE_NOTIFICATION,
2561         STREAM_USAGE_ACCESSIBILITY, STREAM_USAGE_SYSTEM,
2562         STREAM_USAGE_MOVIE, STREAM_USAGE_GAME,
2563         STREAM_USAGE_AUDIOBOOK, STREAM_USAGE_NAVIGATION,
2564         STREAM_USAGE_DTMF, STREAM_USAGE_ENFORCED_TONE,
2565         STREAM_USAGE_ULTRASONIC, STREAM_USAGE_VIDEO_COMMUNICATION
2566     };
2567     std::vector<int32_t> systemUsages = { STREAM_USAGE_VOICE_CALL_ASSISTANT };
2568     usages.insert(usages.end(), systemUsages.begin(), systemUsages.end());
2569     if (std::find(systemUsages.begin(), systemUsages.end(), usage) != systemUsages.end() && !IsSystemApp()) {
2570         MEDIA_LOGI("The caller is not a system app, usage = %{public}d", usage);
2571         return false;
2572     }
2573     if (std::find(contents.begin(), contents.end(), content) == contents.end() ||
2574         std::find(usages.begin(), usages.end(), usage) == usages.end()) {
2575         return false;
2576     }
2577 
2578     if (jsPlayer->audioRendererInfo_.contentType != content ||
2579         jsPlayer->audioRendererInfo_.streamUsage != usage) {
2580         jsPlayer->audioEffectMode_ = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
2581     }
2582 
2583     jsPlayer->audioRendererInfo_ = AudioStandard::AudioRendererInfo {
2584         static_cast<AudioStandard::ContentType>(content),
2585         static_cast<AudioStandard::StreamUsage>(usage),
2586         rendererFlags,
2587         static_cast<AudioStandard::AudioVolumeMode>(volumeMode)
2588     };
2589     return true;
2590 }
2591 
SeekEnqueueTask(AVPlayerNapi * jsPlayer,int32_t time,int32_t mode)2592 void AVPlayerNapi::SeekEnqueueTask(AVPlayerNapi *jsPlayer, int32_t time, int32_t mode)
2593 {
2594     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, time, mode]() {
2595         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSeek Task In", FAKE_POINTER(jsPlayer));
2596         if (jsPlayer->player_ != nullptr) {
2597             (void)jsPlayer->player_->Seek(time, jsPlayer->TransferSeekMode(mode));
2598         }
2599         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSeek Task Out", FAKE_POINTER(jsPlayer));
2600     });
2601     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSeek EnqueueTask In", FAKE_POINTER(jsPlayer));
2602     (void)jsPlayer->taskQue_->EnqueueTask(task);
2603     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSeek Out", FAKE_POINTER(jsPlayer));
2604 }
2605 
JsSetAudioRendererInfo(napi_env env,napi_callback_info info)2606 napi_value AVPlayerNapi::JsSetAudioRendererInfo(napi_env env, napi_callback_info info)
2607 {
2608     MediaTrace trace("AVPlayerNapi::set audioRendererInfo");
2609     napi_value result = nullptr;
2610     napi_get_undefined(env, &result);
2611     MEDIA_LOGI("JsSetAudioRendererInfo In");
2612 
2613     napi_value args[1] = { nullptr };
2614     size_t argCount = 1;
2615     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2616     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2617     napi_valuetype valueType = napi_undefined;
2618     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
2619         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input");
2620         return result;
2621     }
2622     if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_INITIALIZED) {
2623         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2624             "current state is not initialized, unsupport to set audio renderer info");
2625         return result;
2626     }
2627     if (!AVPlayerNapi::JsHandleParameter(env, args[0], jsPlayer)) {
2628         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2629             "invalid parameters, please check the input audio renderer info");
2630         return result;
2631     }
2632     auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
2633         MEDIA_LOGI("SetAudioRendererInfo Task");
2634         if (jsPlayer->player_ != nullptr) {
2635             Format format;
2636             (void)format.PutIntValue(PlayerKeys::CONTENT_TYPE, jsPlayer->audioRendererInfo_.contentType);
2637             (void)format.PutIntValue(PlayerKeys::STREAM_USAGE, jsPlayer->audioRendererInfo_.streamUsage);
2638             (void)format.PutIntValue(PlayerKeys::RENDERER_FLAG, jsPlayer->audioRendererInfo_.rendererFlags);
2639             (void)format.PutIntValue(PlayerKeys::VOLUME_MODE, jsPlayer->audioRendererInfo_.volumeMode);
2640             (void)jsPlayer->player_->SetParameter(format);
2641         }
2642     });
2643     (void)jsPlayer->taskQue_->EnqueueTask(task);
2644     MEDIA_LOGI("JsSetAudioRendererInfo Out");
2645     return result;
2646 }
2647 
JsGetAudioRendererInfo(napi_env env,napi_callback_info info)2648 napi_value AVPlayerNapi::JsGetAudioRendererInfo(napi_env env, napi_callback_info info)
2649 {
2650     MediaTrace trace("AVPlayerNapi::get audioRendererInfo");
2651     napi_value result = nullptr;
2652     napi_get_undefined(env, &result);
2653     MEDIA_LOGI("JsGetAudioRendererInfo In");
2654 
2655     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2656     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2657 
2658     int32_t content = static_cast<int32_t>(jsPlayer->audioRendererInfo_.contentType);
2659     int32_t usage = static_cast<int32_t>(jsPlayer->audioRendererInfo_.streamUsage);
2660     int32_t rendererFlags = jsPlayer->audioRendererInfo_.rendererFlags;
2661     int32_t volumeMode = static_cast<int32_t>(jsPlayer->audioRendererInfo_.volumeMode);
2662     (void)napi_create_object(env, &result);
2663     CommonNapi::SetPropertyInt32(env, result, "content", content);
2664     CommonNapi::SetPropertyInt32(env, result, "usage", usage);
2665     CommonNapi::SetPropertyInt32(env, result, "rendererFlags", rendererFlags);
2666     CommonNapi::SetPropertyInt32(env, result, "volumeMode", volumeMode);
2667     MEDIA_LOGI("JsGetAudioRendererInfo Out");
2668     return result;
2669 }
2670 
JsGetCurrentTime(napi_env env,napi_callback_info info)2671 napi_value AVPlayerNapi::JsGetCurrentTime(napi_env env, napi_callback_info info)
2672 {
2673     MediaTrace trace("AVPlayerNapi::get currentTime");
2674     napi_value result = nullptr;
2675     napi_get_undefined(env, &result);
2676     MEDIA_LOGD("JsGetCurrentTime In");
2677 
2678     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2679     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2680 
2681     int32_t currentTime = -1;
2682     if (jsPlayer->IsControllable()) {
2683         if (!jsPlayer->reportMediaProgressCallbackflag_ && jsPlayer->player_ != nullptr) {
2684             auto ret = jsPlayer->player_->GetCurrentTime(currentTime);
2685             currentTime = ret == MSERR_OK ? currentTime : -1;
2686             jsPlayer->HandleListenerStateChange("timeUpdate", true);
2687         } else {
2688             currentTime = jsPlayer->position_;
2689         }
2690     }
2691 
2692     if (jsPlayer->IsLiveSource() && jsPlayer->dataSrcCb_ == nullptr) {
2693         currentTime = -1;
2694     }
2695     napi_value value = nullptr;
2696     (void)napi_create_int32(env, currentTime, &value);
2697     std::string curState = jsPlayer->GetCurrentState();
2698     if (currentTime != -1) {
2699         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsGetCurrenTime Out, state %{public}s, time %{public}d",
2700             FAKE_POINTER(jsPlayer), curState.c_str(), currentTime);
2701     }
2702     return value;
2703 }
2704 
JsGetPlaybackPosition(napi_env env,napi_callback_info info)2705 napi_value AVPlayerNapi::JsGetPlaybackPosition(napi_env env, napi_callback_info info)
2706 {
2707     MediaTrace trace("AVPlayerNapi::get playbackPosition");
2708     napi_value result = nullptr;
2709     napi_get_undefined(env, &result);
2710     MEDIA_LOGD("JsGetPlaybackPosition In");
2711 
2712     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2713     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2714     CHECK_AND_RETURN_RET_LOG(jsPlayer->player_ != nullptr, result, "failed to check player_");
2715 
2716     std::string curState = jsPlayer->GetCurrentState();
2717     if (curState == AVPlayerState::STATE_PLAYING &&
2718         curState == AVPlayerState::STATE_PAUSED &&
2719         curState == AVPlayerState::STATE_PREPARED &&
2720         curState == AVPlayerState::STATE_COMPLETED) {
2721         return CommonNapi::ThrowError(env, MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2722             "current state is not prepared/playing/paused/completed, not support get playback position");
2723     }
2724 
2725     int32_t playbackPosition = 0;
2726     (void)jsPlayer->player_->GetPlaybackPosition(playbackPosition);
2727     if (playbackPosition != 0) {
2728         MEDIA_LOGD("0x%{public}06" PRIXPTR " JsGetPlaybackPosition Out, state %{public}s, time: %{public}d",
2729             FAKE_POINTER(jsPlayer), curState.c_str(), playbackPosition);
2730     }
2731 
2732     napi_value value = nullptr;
2733     napi_status status = napi_create_int32(env, playbackPosition, &value);
2734     if (status != napi_ok) {
2735         MEDIA_LOGE("JsGetPlaybackPosition status != napi_ok");
2736     }
2737     return value;
2738 }
2739 
JsForceLoadVideo(napi_env env,napi_callback_info info)2740 napi_value AVPlayerNapi::JsForceLoadVideo(napi_env env, napi_callback_info info)
2741 {
2742     MediaTrace trace("AVPlayerNapi::ForceLoadVideo");
2743     napi_value result = nullptr;
2744     napi_get_undefined(env, &result);
2745 
2746     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
2747     napi_value args[1] = { nullptr };
2748     size_t argCount = 1;
2749 
2750     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2751     CHECK_AND_RETURN_RET_LOG(promiseCtx->napi != nullptr, result, "failed to GetJsInstance");
2752     CHECK_AND_RETURN_RET_LOG(promiseCtx->napi->player_ != nullptr, result, "failed to check player_");
2753     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
2754 
2755     bool isForceLoadVideo = false;
2756     if (!IsSystemApp()) {
2757         promiseCtx->SignError(MSERR_EXT_API9_PERMISSION_DENIED, "only system app support this function");
2758     } else if (napi_valuetype valueType = napi_undefined; napi_typeof(env, args[0], &valueType) != napi_ok
2759         || valueType != napi_boolean || napi_get_value_bool(env, args[0], &isForceLoadVideo) != napi_ok) {
2760         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "input param type is not boolean");
2761     }
2762 
2763     // only if no errors can exec task
2764     if (!promiseCtx->errFlag) {
2765         promiseCtx->asyncTask = promiseCtx->napi->ForceLoadVideoTask(isForceLoadVideo);
2766         promiseCtx->napi->isForceLoadVideo_ = isForceLoadVideo;
2767     }
2768     napi_value resource = nullptr;
2769     napi_create_string_utf8(env, "JsForceLoadVideo", NAPI_AUTO_LENGTH, &resource);
2770     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
2771         auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
2772         CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
2773         promiseCtx->CheckTaskResult();
2774     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
2775     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
2776     promiseCtx.release();
2777     return result;
2778 }
2779 
ForceLoadVideoTask(bool status)2780 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ForceLoadVideoTask(bool status)
2781 {
2782     auto task = std::make_shared<TaskHandler<TaskRet>>([this, status] {
2783         std::unique_lock<std::mutex> lock(taskMutex_);
2784         auto state = GetCurrentState();
2785         CHECK_AND_RETURN_RET(state == AVPlayerState::STATE_INITIALIZED || state == AVPlayerState::STATE_STOPPED,
2786             TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "state unsupport this operation"));
2787         auto ret = player_->ForceLoadVideo(status);
2788         CHECK_AND_RETURN_RET(ret == MSERR_OK,
2789             TaskRet(MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret)), "ForceLoadVideo failed"));
2790         return TaskRet(MSERR_EXT_API9_OK, "Success");
2791     });
2792     (void)taskQue_->EnqueueTask(task);
2793     return task;
2794 }
2795 
JsGetDuration(napi_env env,napi_callback_info info)2796 napi_value AVPlayerNapi::JsGetDuration(napi_env env, napi_callback_info info)
2797 {
2798     MediaTrace trace("AVPlayerNapi::get duration");
2799     napi_value result = nullptr;
2800     napi_get_undefined(env, &result);
2801     MEDIA_LOGD("JsGetDuration In");
2802 
2803     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2804     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2805 
2806     int32_t duration = -1;
2807     if (jsPlayer->IsControllable() && !jsPlayer->IsLiveSource()) {
2808         duration = jsPlayer->duration_;
2809     }
2810 
2811     napi_value value = nullptr;
2812     (void)napi_create_int32(env, duration, &value);
2813     std::string curState = jsPlayer->GetCurrentState();
2814     MEDIA_LOGD("JsGetDuration Out, state %{public}s, duration %{public}d", curState.c_str(), duration);
2815     return value;
2816 }
2817 
IsControllable()2818 bool AVPlayerNapi::IsControllable()
2819 {
2820     auto state = GetCurrentState();
2821     if (state == AVPlayerState::STATE_PREPARED || state == AVPlayerState::STATE_PLAYING ||
2822         state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_COMPLETED) {
2823         return true;
2824     } else {
2825         return false;
2826     }
2827 }
2828 
CanSetPlayRange()2829 bool AVPlayerNapi::CanSetPlayRange()
2830 {
2831     auto state = GetCurrentState();
2832     if (state == AVPlayerState::STATE_INITIALIZED || state == AVPlayerState::STATE_PREPARED ||
2833         state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_STOPPED ||
2834         state == AVPlayerState::STATE_COMPLETED) {
2835         return true;
2836     }
2837     return false;
2838 }
2839 
CanSetSuperResolution()2840 bool AVPlayerNapi::CanSetSuperResolution()
2841 {
2842     auto state = GetCurrentState();
2843     if (state == AVPlayerState::STATE_INITIALIZED || state == AVPlayerState::STATE_PREPARED ||
2844         state == AVPlayerState::STATE_PLAYING || state == AVPlayerState::STATE_PAUSED ||
2845         state == AVPlayerState::STATE_STOPPED || state == AVPlayerState::STATE_COMPLETED) {
2846         return true;
2847     }
2848     return false;
2849 }
2850 
CanCameraPostprocessing()2851 bool AVPlayerNapi::CanCameraPostprocessing()
2852 {
2853     auto state = GetCurrentState();
2854     if (state == AVPlayerState::STATE_INITIALIZED) {
2855         return true;
2856     }
2857     return false;
2858 }
2859 
GetCurrentState()2860 std::string AVPlayerNapi::GetCurrentState()
2861 {
2862     if (isReleased_.load()) {
2863         return AVPlayerState::STATE_RELEASED;
2864     }
2865 
2866     std::string curState = AVPlayerState::STATE_ERROR;
2867     static const std::map<PlayerStates, std::string> stateMap = {
2868         {PLAYER_IDLE, AVPlayerState::STATE_IDLE},
2869         {PLAYER_INITIALIZED, AVPlayerState::STATE_INITIALIZED},
2870         {PLAYER_PREPARED, AVPlayerState::STATE_PREPARED},
2871         {PLAYER_STARTED, AVPlayerState::STATE_PLAYING},
2872         {PLAYER_PAUSED, AVPlayerState::STATE_PAUSED},
2873         {PLAYER_STOPPED, AVPlayerState::STATE_STOPPED},
2874         {PLAYER_PLAYBACK_COMPLETE, AVPlayerState::STATE_COMPLETED},
2875         {PLAYER_STATE_ERROR, AVPlayerState::STATE_ERROR},
2876     };
2877 
2878     if (stateMap.find(state_) != stateMap.end()) {
2879         curState = stateMap.at(state_);
2880     }
2881     return curState;
2882 }
2883 
JsGetState(napi_env env,napi_callback_info info)2884 napi_value AVPlayerNapi::JsGetState(napi_env env, napi_callback_info info)
2885 {
2886     MediaTrace trace("AVPlayerNapi::get state");
2887     napi_value result = nullptr;
2888     napi_get_undefined(env, &result);
2889     MEDIA_LOGD("JsGetState In");
2890 
2891     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2892     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2893 
2894     std::string curState = jsPlayer->GetCurrentState();
2895     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsGetState curState: %{public}s ",
2896         FAKE_POINTER(jsPlayer), curState.c_str());
2897     napi_value value = nullptr;
2898     (void)napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &value);
2899     MEDIA_LOGD("JsGetState Out");
2900     return value;
2901 }
2902 
JsGetWidth(napi_env env,napi_callback_info info)2903 napi_value AVPlayerNapi::JsGetWidth(napi_env env, napi_callback_info info)
2904 {
2905     MediaTrace trace("AVPlayerNapi::get width");
2906     napi_value result = nullptr;
2907     napi_get_undefined(env, &result);
2908     MEDIA_LOGI("JsGetWidth");
2909 
2910     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2911     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2912 
2913     int32_t width = 0;
2914     if (jsPlayer->IsControllable()) {
2915         width = jsPlayer->width_;
2916     }
2917 
2918     napi_value value = nullptr;
2919     (void)napi_create_int32(env, width, &value);
2920     return value;
2921 }
2922 
JsGetHeight(napi_env env,napi_callback_info info)2923 napi_value AVPlayerNapi::JsGetHeight(napi_env env, napi_callback_info info)
2924 {
2925     MediaTrace trace("AVPlayerNapi::get height");
2926     napi_value result = nullptr;
2927     napi_get_undefined(env, &result);
2928     MEDIA_LOGI("JsGetHeight");
2929 
2930     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2931     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2932 
2933     int32_t height = 0;
2934     if (jsPlayer->IsControllable()) {
2935         height = jsPlayer->height_;
2936     }
2937 
2938     napi_value value = nullptr;
2939     (void)napi_create_int32(env, height, &value);
2940     return value;
2941 }
2942 
JsGetTrackDescription(napi_env env,napi_callback_info info)2943 napi_value AVPlayerNapi::JsGetTrackDescription(napi_env env, napi_callback_info info)
2944 {
2945     MediaTrace trace("AVPlayerNapi::get trackDescription");
2946     napi_value result = nullptr;
2947     napi_get_undefined(env, &result);
2948     MEDIA_LOGI("GetTrackDescription In");
2949 
2950     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
2951     napi_value args[1] = { nullptr };
2952     size_t argCount = 1;
2953     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2954     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
2955     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
2956 
2957     auto jsPlayer = promiseCtx->napi;
2958     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2959     MEDIA_LOGD("0x%{public}06" PRIXPTR " JsGetTrackDescription EnqueueTask In", FAKE_POINTER(jsPlayer));
2960     promiseCtx->asyncTask = jsPlayer->GetTrackDescriptionTask(promiseCtx);
2961     MEDIA_LOGD("0x%{public}06" PRIXPTR " JsGetTrackDescription EnqueueTask Out", FAKE_POINTER(jsPlayer));
2962 
2963     // async work
2964     napi_value resource = nullptr;
2965     napi_create_string_utf8(env, "JsGetTrackDescription", NAPI_AUTO_LENGTH, &resource);
2966     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
2967         [](napi_env env, void *data) {
2968             MEDIA_LOGI("Wait JsGetTrackDescription Task Start");
2969             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
2970             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
2971             if (promiseCtx->asyncTask) {
2972                 auto result = promiseCtx->asyncTask->GetResult();
2973                 if (!result.HasResult()) {
2974                     return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2975                                                  "task has been cleared");
2976                 }
2977                 if (result.Value().first != MSERR_EXT_API9_OK) {
2978                     return promiseCtx->SignError(result.Value().first, result.Value().second);
2979                 }
2980                 promiseCtx->JsResult = std::make_unique<MediaJsResultArray>(promiseCtx->trackInfoVec_);
2981             }
2982             MEDIA_LOGI("Wait JsGetTrackDescription Task End");
2983         },
2984         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
2985     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
2986     promiseCtx.release();
2987     MEDIA_LOGI("GetTrackDescription Out");
2988     return result;
2989 }
2990 
GetTrackDescriptionTask(const std::unique_ptr<AVPlayerContext> & promiseCtx)2991 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::GetTrackDescriptionTask(const std::unique_ptr<AVPlayerContext>
2992                                                                             &promiseCtx)
2993 {
2994     auto task = std::make_shared<TaskHandler<TaskRet>>([this, &trackInfo = promiseCtx->trackInfoVec_]() {
2995         MEDIA_LOGI("0x%{public}06" PRIXPTR " GetTrackDescription Task In", FAKE_POINTER(this));
2996         std::unique_lock<std::mutex> lock(taskMutex_);
2997         trackInfo.clear();
2998         if (IsControllable()) {
2999             (void)player_->GetVideoTrackInfo(trackInfo);
3000             (void)player_->GetAudioTrackInfo(trackInfo);
3001             (void)player_->GetSubtitleTrackInfo(trackInfo);
3002         } else {
3003             return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3004                            "current state unsupport get track description");
3005         }
3006         MEDIA_LOGI("0x%{public}06" PRIXPTR " GetTrackDescription Task Out", FAKE_POINTER(this));
3007         return TaskRet(MSERR_EXT_API9_OK, "Success");
3008     });
3009     (void)taskQue_->EnqueueTask(task);
3010     return task;
3011 }
3012 
JsGetSelectedTracks(napi_env env,napi_callback_info info)3013 napi_value AVPlayerNapi::JsGetSelectedTracks(napi_env env, napi_callback_info info)
3014 {
3015     MediaTrace trace("AVPlayerNapi::get selected tracks");
3016     napi_value result = nullptr;
3017     napi_get_undefined(env, &result);
3018     MEDIA_LOGI("JsGetSelectedTracks In");
3019 
3020     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
3021     napi_value args[1] = { nullptr };
3022     size_t argCount = 1;
3023     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3024     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
3025     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
3026     // async work
3027     napi_value resource = nullptr;
3028     napi_create_string_utf8(env, "JsGetSelectedTracks", NAPI_AUTO_LENGTH, &resource);
3029     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
3030             MEDIA_LOGI("JsGetSelectedTracks Task");
3031             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
3032             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
3033 
3034             auto jsPlayer = promiseCtx->napi;
3035             if (jsPlayer == nullptr) {
3036                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
3037             }
3038 
3039             std::vector<int32_t> trackIndex;
3040             if (jsPlayer->IsControllable()) {
3041                 int32_t videoIndex = -1;
3042                 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_VID, videoIndex);
3043                 if (videoIndex != -1) {
3044                     trackIndex.push_back(videoIndex);
3045                 }
3046 
3047                 int32_t audioIndex = -1;
3048                 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_AUD, audioIndex);
3049                 if (audioIndex != -1) {
3050                     trackIndex.push_back(audioIndex);
3051                 }
3052 
3053                 int32_t subtitleIndex = -1;
3054                 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_SUBTITLE, subtitleIndex);
3055                 if (subtitleIndex != -1) {
3056                     trackIndex.push_back(subtitleIndex);
3057                 }
3058             } else {
3059                 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3060                     "current state unsupport get current selections");
3061             }
3062             promiseCtx->JsResult = std::make_unique<MediaJsResultIntArray>(trackIndex);
3063         },
3064         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
3065     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
3066     promiseCtx.release();
3067     MEDIA_LOGI("JsGetSelectedTracks Out");
3068     return result;
3069 }
3070 
HandleSelectTrack(std::unique_ptr<AVPlayerContext> & promiseCtx,napi_env env,napi_value args[],size_t argCount)3071 void AVPlayerNapi::HandleSelectTrack(std::unique_ptr<AVPlayerContext> &promiseCtx, napi_env env,
3072     napi_value args[], size_t argCount)
3073 {
3074     napi_valuetype valueType = napi_undefined;
3075     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
3076         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
3077         return;
3078     }
3079 
3080     auto jsPlayer = promiseCtx->napi;
3081     napi_status status = napi_get_value_int32(env, args[0], &jsPlayer->index_);
3082     if (status != napi_ok || jsPlayer->index_ < 0) {
3083         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the track index");
3084         return;
3085     }
3086 
3087     if (argCount > 1) {
3088         if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
3089             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "switch mode is not number");
3090             return;
3091         }
3092         status = napi_get_value_int32(env, args[1], &jsPlayer->mode_);
3093         if (status != napi_ok || jsPlayer->mode_ < SWITCH_SMOOTH || jsPlayer->mode_ > SWITCH_CLOSEST) {
3094             promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please switch seek mode");
3095             return;
3096         }
3097     }
3098 
3099     if (!jsPlayer->IsControllable()) {
3100         promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3101             "current state is not prepared/playing/paused/completed, unsupport selectTrack operation");
3102         return;
3103     }
3104 }
3105 
JsSelectTrack(napi_env env,napi_callback_info info)3106 napi_value AVPlayerNapi::JsSelectTrack(napi_env env, napi_callback_info info)
3107 {
3108     MediaTrace trace("AVPlayerNapi::selectTrack");
3109     MEDIA_LOGI("JsSelectTrack In");
3110     napi_value result = nullptr;
3111     napi_get_undefined(env, &result);
3112 
3113     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
3114     size_t argCount = 3; // 2 prarm, args[0]:index args[1]:SwitchMode callbackRef
3115     napi_value args[ARRAY_ARG_COUNTS_THREE] = { nullptr };
3116     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3117     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[argCount -1]);
3118     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
3119     CHECK_AND_RETURN_RET_LOG(promiseCtx->napi != nullptr, result, "failed to GetJsInstanceWithParameter");
3120 
3121     promiseCtx->napi->HandleSelectTrack(promiseCtx, env, args, argCount);
3122 
3123     // async work
3124     napi_value resource = nullptr;
3125     napi_create_string_utf8(env, "JsSelectTrack ", NAPI_AUTO_LENGTH, &resource);
3126     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
3127         MEDIA_LOGI("JsSelectTrack Task");
3128         auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
3129         CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
3130 
3131         CHECK_AND_RETURN(!promiseCtx->errFlag);
3132 
3133         auto jsPlayer = promiseCtx->napi;
3134         if (jsPlayer == nullptr) {
3135             return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
3136         }
3137 
3138         auto task = std::make_shared<TaskHandler<void>>([jsPlayer, index = jsPlayer->index_, mode = jsPlayer->mode_]() {
3139             MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Task In", FAKE_POINTER(jsPlayer));
3140             if (jsPlayer->player_ != nullptr) {
3141                 (void)jsPlayer->player_->SelectTrack(index, jsPlayer->TransferSwitchMode(mode));
3142             }
3143             MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Task Out", FAKE_POINTER(jsPlayer));
3144         });
3145         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack EnqueueTask In", FAKE_POINTER(jsPlayer));
3146         (void)jsPlayer->taskQue_->EnqueueTask(task);
3147         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Out", FAKE_POINTER(jsPlayer));
3148     },
3149     MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
3150     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
3151     promiseCtx.release();
3152     MEDIA_LOGI("JsSelectTrack Out");
3153     return result;
3154 }
3155 
JsDeselectTrack(napi_env env,napi_callback_info info)3156 napi_value AVPlayerNapi::JsDeselectTrack(napi_env env, napi_callback_info info)
3157 {
3158     MediaTrace trace("AVPlayerNapi::deselectTrack");
3159     MEDIA_LOGI("deselectTrack In");
3160     napi_value result = nullptr;
3161     napi_get_undefined(env, &result);
3162 
3163     size_t argCount = 1;     // 1 prarm, args[0]:index
3164     napi_value args[1] = { nullptr };
3165     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3166     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
3167 
3168     napi_valuetype valueType = napi_undefined;
3169     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
3170         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
3171         return result;
3172     }
3173 
3174     int32_t index = -1;
3175     napi_status status = napi_get_value_int32(env, args[0], &index);
3176     if (status != napi_ok || index < 0) {
3177         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the track index");
3178         return result;
3179     }
3180 
3181     if (!jsPlayer->IsControllable()) {
3182         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3183             "current state is not prepared/playing/paused/completed, unsupport deselecttrack operation");
3184         return result;
3185     }
3186 
3187     auto task = std::make_shared<TaskHandler<void>>([jsPlayer, index]() {
3188         MEDIA_LOGI("deselectTrack Task");
3189         if (jsPlayer->player_ != nullptr) {
3190             (void)jsPlayer->player_->DeselectTrack(index);
3191         }
3192         MEDIA_LOGI("deselectTrack Task end");
3193     });
3194     (void)jsPlayer->taskQue_->EnqueueTask(task);
3195     return result;
3196 }
3197 
JsGetCurrentTrack(napi_env env,napi_callback_info info)3198 napi_value AVPlayerNapi::JsGetCurrentTrack(napi_env env, napi_callback_info info)
3199 {
3200     MediaTrace trace("AVPlayerNapi::JsGetCurrentTrack");
3201     MEDIA_LOGI("GetCurrentTrack In");
3202     napi_value result = nullptr;
3203     napi_get_undefined(env, &result);
3204 
3205     size_t argCount = 2; // 2 param: trackType + callback
3206     napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr };
3207     auto promiseCtx = std::make_unique<AVPlayerContext>(env);
3208     promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3209     CHECK_AND_RETURN_RET_LOG(promiseCtx->napi != nullptr, result, "failed to GetJsInstanceWithParameter");
3210     promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
3211     promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
3212 
3213     promiseCtx->napi->GetCurrentTrackTask(promiseCtx, env, args[0]);
3214 
3215     // async work
3216     napi_value resource = nullptr;
3217     napi_create_string_utf8(env, "JsGetCurrentTrack", NAPI_AUTO_LENGTH, &resource);
3218     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
3219         [](napi_env env, void *data) {
3220             MEDIA_LOGI("GetCurrentTrack Task");
3221             auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
3222             CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
3223             CHECK_AND_RETURN_LOG(promiseCtx->asyncTask != nullptr, "asyncTask is nullptr!");
3224             auto result = promiseCtx->asyncTask->GetResult();
3225             if (result.HasResult() && result.Value().first != MSERR_EXT_API9_OK) {
3226                 promiseCtx->SignError(result.Value().first, result.Value().second);
3227             } else {
3228                 promiseCtx->JsResult = std::make_unique<MediaJsResultInt>(stoi(result.Value().second));
3229             }
3230             MEDIA_LOGI("GetCurrentTrack Task end");
3231         },
3232         MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
3233     napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
3234     promiseCtx.release();
3235     return result;
3236 }
3237 
GetCurrentTrackTask(std::unique_ptr<AVPlayerContext> & promiseCtx,napi_env env,napi_value args)3238 void AVPlayerNapi::GetCurrentTrackTask(std::unique_ptr<AVPlayerContext> &promiseCtx, napi_env env, napi_value args)
3239 {
3240     if (!promiseCtx->napi->IsControllable()) {
3241         promiseCtx->napi->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3242             "current state is not prepared/playing/paused/completed, unsupport getCurrentTrack operation");
3243         return;
3244     }
3245 
3246     napi_valuetype valueType = napi_undefined;
3247     if (args == nullptr || napi_typeof(env, args, &valueType) != napi_ok || valueType != napi_number) {
3248         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
3249         return;
3250     }
3251 
3252     int32_t trackType = MediaType::MEDIA_TYPE_AUD;
3253     napi_status status = napi_get_value_int32(env, args, &trackType);
3254     if (status != napi_ok || trackType < MediaType::MEDIA_TYPE_AUD || trackType > MediaType::MEDIA_TYPE_VID) {
3255         promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid track Type");
3256         return;
3257     }
3258 
3259     auto task = std::make_shared<TaskHandler<TaskRet>>([this, trackType]() {
3260         MEDIA_LOGI("GetCurrentTrack Task In");
3261         std::unique_lock<std::mutex> lock(taskMutex_);
3262         CHECK_AND_RETURN_RET(IsControllable(), TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
3263             "current state is not prepared/playing/paused/completed, unsupport getCurrentTrack operation"));
3264 
3265         int32_t index = 0;
3266         int32_t ret = player_->GetCurrentTrack(trackType, index);
3267         if (ret != MSERR_OK) {
3268             auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
3269             return TaskRet(errCode, "failed to GetCurrentTrack");
3270         }
3271         MEDIA_LOGI("GetCurrentTrack Task Out");
3272         return TaskRet(MSERR_EXT_API9_OK, std::to_string(index));
3273     });
3274     (void)taskQue_->EnqueueTask(task);
3275     promiseCtx->asyncTask = task;
3276     return;
3277 }
3278 
DeviceChangeCallbackOn(AVPlayerNapi * jsPlayer,std::string callbackName)3279 void AVPlayerNapi::DeviceChangeCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName)
3280 {
3281     if (jsPlayer == nullptr) {
3282         deviceChangeCallbackflag_ = false;
3283         return;
3284     }
3285     if (callbackName == "audioOutputDeviceChangeWithInfo") {
3286         deviceChangeCallbackflag_ = true;
3287     }
3288     if (jsPlayer->player_ != nullptr && deviceChangeCallbackflag_) {
3289         (void)jsPlayer->player_->SetDeviceChangeCbStatus(deviceChangeCallbackflag_);
3290     }
3291 }
3292 
DeviceChangeCallbackOff(AVPlayerNapi * jsPlayer,std::string callbackName)3293 void AVPlayerNapi::DeviceChangeCallbackOff(AVPlayerNapi *jsPlayer, std::string callbackName)
3294 {
3295     if (jsPlayer != nullptr && deviceChangeCallbackflag_ && callbackName == "audioOutputDeviceChangeWithInfo") {
3296         deviceChangeCallbackflag_ = false;
3297         if (jsPlayer->player_ != nullptr) {
3298             (void)jsPlayer->player_->SetDeviceChangeCbStatus(deviceChangeCallbackflag_);
3299         }
3300     }
3301 }
3302 
HandleListenerStateChange(std::string callbackName,bool state)3303 void AVPlayerNapi::HandleListenerStateChange(std::string callbackName, bool state)
3304 {
3305     CHECK_AND_RETURN_LOG(player_ != nullptr, "player is nullptr");
3306 
3307     if (callbackName == "amplitudeUpdate") {
3308         return (void)player_->SetMaxAmplitudeCbStatus(state);
3309     }
3310 
3311     if (callbackName == "timeUpdate") {
3312         reportMediaProgressCallbackflag_ = state;
3313         return (void)player_->EnableReportMediaProgress(state);
3314     }
3315 
3316     if (callbackName == "audioInterrupt") {
3317         return (void)player_->EnableReportAudioInterrupt(state);
3318     }
3319 }
3320 
SeiMessageCallbackOn(AVPlayerNapi * jsPlayer,std::string callbackName,const std::vector<int32_t> & payloadTypes)3321 void AVPlayerNapi::SeiMessageCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName,
3322     const std::vector<int32_t> &payloadTypes)
3323 {
3324     if (callbackName == "seiMessageReceived") {
3325         seiMessageCallbackflag_ = true;
3326     }
3327 
3328     if (jsPlayer->player_ != nullptr && seiMessageCallbackflag_) {
3329         MEDIA_LOGI("seiMessageCallbackflag_ = %{public}d", seiMessageCallbackflag_);
3330         (void)jsPlayer->player_->SetSeiMessageCbStatus(seiMessageCallbackflag_, payloadTypes);
3331     }
3332 }
3333 
JsSetOnCallback(napi_env env,napi_callback_info info)3334 napi_value AVPlayerNapi::JsSetOnCallback(napi_env env, napi_callback_info info)
3335 {
3336     MediaTrace trace("AVPlayerNapi::on");
3337     napi_value result = nullptr;
3338     napi_get_undefined(env, &result);
3339     MEDIA_LOGD("JsSetOnCallback In");
3340 
3341     napi_value args[ARRAY_ARG_COUNTS_THREE] = { nullptr }; // args[0]:type, args[1]: payloadTypes  args[2]:callback
3342     size_t argCount = ARRAY_ARG_COUNTS_THREE;
3343     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3344     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
3345     if (argCount < ARRAY_ARG_COUNTS_TWO || argCount > ARRAY_ARG_COUNTS_THREE) {
3346         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Mandatory parameters are left unspecified.");
3347         return result;
3348     }
3349 
3350     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
3351         jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to on event");
3352         return result;
3353     }
3354 
3355     CHECK_AND_RETURN_RET_NOLOG(
3356         VerifyExpectedType({ env, args[0], napi_string }, jsPlayer, "type should be string."), result);
3357     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
3358     jsPlayer->hasSetStateChangeCb_ |= (callbackName == "stateChange");
3359 
3360     napi_ref ref = nullptr;
3361     if (argCount == ARGS_THREE) {
3362         CHECK_AND_RETURN_RET_NOLOG(
3363             VerifyExpectedType({ env, args[1], napi_object }, jsPlayer, "payloadTypes should be an Array."), result);
3364         CHECK_AND_RETURN_RET_NOLOG(
3365             VerifyExpectedType({ env, args[ARGS_TWO], napi_function }, jsPlayer, "param should be function."), result);
3366         std::vector<int32_t> payloadTypes = {};
3367         (void)CommonNapi::GetIntArrayArgument(env, args[1], payloadTypes);
3368         jsPlayer->SeiMessageCallbackOn(jsPlayer, callbackName, payloadTypes);
3369         napi_status status = napi_create_reference(env, args[ARGS_TWO], 1, &ref);
3370         CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
3371     } else if (argCount == ARGS_TWO) {
3372         CHECK_AND_RETURN_RET_NOLOG(
3373             VerifyExpectedType({env, args[1], napi_function}, jsPlayer, "param should be function."), result);
3374         jsPlayer->HandleListenerStateChange(callbackName, true);
3375         napi_status status = napi_create_reference(env, args[1], 1, &ref);
3376         CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
3377     }
3378     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
3379         jsPlayer->SaveCallbackReference(callbackName, autoRef);
3380     MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetOnCallback callbackName: %{public}s success",
3381         FAKE_POINTER(jsPlayer), callbackName.c_str());
3382     return result;
3383 }
3384 
VerifyExpectedType(const NapiTypeCheckUnit & unit,AVPlayerNapi * jsPlayer,const std::string & msg)3385 bool AVPlayerNapi::VerifyExpectedType(const NapiTypeCheckUnit &unit, AVPlayerNapi *jsPlayer, const std::string &msg)
3386 {
3387     napi_valuetype tmpType;
3388     CHECK_AND_RETURN_RET_NOLOG(
3389         napi_typeof(unit.env, unit.param, &tmpType) != napi_ok || tmpType != unit.expectedType, true);
3390     jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, msg);
3391     return false;
3392 }
3393 
SeiMessageCallbackOff(AVPlayerNapi * jsPlayer,std::string & callbackName,const std::vector<int32_t> & payloadTypes)3394 void AVPlayerNapi::SeiMessageCallbackOff(AVPlayerNapi *jsPlayer, std::string &callbackName,
3395     const std::vector<int32_t> &payloadTypes)
3396 {
3397     if (jsPlayer == nullptr || !seiMessageCallbackflag_ || callbackName != "seiMessageReceived") {
3398         return;
3399     }
3400     seiMessageCallbackflag_ = false;
3401     if (jsPlayer->player_ == nullptr) {
3402         return;
3403     }
3404     (void)jsPlayer->player_->SetSeiMessageCbStatus(seiMessageCallbackflag_, payloadTypes);
3405 }
3406 
JsClearOnCallback(napi_env env,napi_callback_info info)3407 napi_value AVPlayerNapi::JsClearOnCallback(napi_env env, napi_callback_info info)
3408 {
3409     MediaTrace trace("AVPlayerNapi::off");
3410     napi_value result = nullptr;
3411     napi_get_undefined(env, &result);
3412     MEDIA_LOGD("JsClearOnCallback In");
3413 
3414     napi_value args[ARRAY_ARG_COUNTS_THREE] = { nullptr }; // args[0]:type, args[1]: payloadTypes  args[2]:callback
3415     size_t argCount = 3;
3416     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
3417     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
3418 
3419     if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
3420         return result;
3421     }
3422 
3423     napi_valuetype valueType0 = napi_undefined;
3424     if (argCount < 1) {
3425         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Mandatory parameters are left unspecified.");
3426         return result;
3427     }
3428 
3429     if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
3430         jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "type should be string.");
3431         return result;
3432     }
3433 
3434     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
3435     jsPlayer->hasSetStateChangeCb_ &= (callbackName != "stateChange");
3436     MEDIA_LOGI("0x%{public}06" PRIXPTR " set callbackName: %{public}s", FAKE_POINTER(jsPlayer), callbackName.c_str());
3437     if (callbackName != "seiMessageReceived") {
3438         jsPlayer->HandleListenerStateChange(callbackName, false);
3439         jsPlayer->ClearCallbackReference(callbackName);
3440         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsClearOnCallback success", FAKE_POINTER(jsPlayer));
3441         return result;
3442     }
3443 
3444     napi_valuetype valueType1 = napi_undefined;
3445     if (napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_object) {
3446         jsPlayer->SeiMessageCallbackOff(jsPlayer, callbackName, {});
3447         jsPlayer->ClearCallbackReference(callbackName);
3448         MEDIA_LOGI("0x%{public}06" PRIXPTR " JsClearOnCallback success", FAKE_POINTER(jsPlayer));
3449         return result;
3450     }
3451     std::vector<int32_t> payloadTypes = {};
3452     if (CommonNapi::GetIntArrayArgument(env, args[1], payloadTypes)) {
3453         jsPlayer->SeiMessageCallbackOff(jsPlayer, callbackName, payloadTypes);
3454     } else {
3455         MEDIA_LOGD("The array is empty, no processing is performed.");
3456     }
3457 
3458     return result;
3459 }
3460 
SaveCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)3461 void AVPlayerNapi::SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
3462 {
3463     std::lock_guard<std::mutex> lock(mutex_);
3464     refMap_[callbackName] = ref;
3465     if (playerCb_ != nullptr) {
3466         playerCb_->SaveCallbackReference(callbackName, ref);
3467     }
3468 }
3469 
ClearCallbackReference()3470 void AVPlayerNapi::ClearCallbackReference()
3471 {
3472     std::lock_guard<std::mutex> lock(mutex_);
3473     if (playerCb_ != nullptr) {
3474         playerCb_->ClearCallbackReference();
3475     }
3476     refMap_.clear();
3477 }
3478 
ClearCallbackReference(const std::string & callbackName)3479 void AVPlayerNapi::ClearCallbackReference(const std::string &callbackName)
3480 {
3481     std::lock_guard<std::mutex> lock(mutex_);
3482     if (playerCb_ != nullptr) {
3483         playerCb_->ClearCallbackReference(callbackName);
3484     }
3485     refMap_.erase(callbackName);
3486 }
3487 
NotifyDuration(int32_t duration)3488 void AVPlayerNapi::NotifyDuration(int32_t duration)
3489 {
3490     duration_ = duration;
3491 }
3492 
NotifyPosition(int32_t position)3493 void AVPlayerNapi::NotifyPosition(int32_t position)
3494 {
3495     position_ = position;
3496 }
3497 
NotifyState(PlayerStates state)3498 void AVPlayerNapi::NotifyState(PlayerStates state)
3499 {
3500     std::lock_guard<std::mutex> lock(taskMutex_);
3501     if (state_ != state) {
3502         state_ = state;
3503         MEDIA_LOGI("0x%{public}06" PRIXPTR " notify %{public}s", FAKE_POINTER(this), GetCurrentState().c_str());
3504         stopWait_ = true;
3505         stateChangeCond_.notify_all();
3506     }
3507 }
3508 
NotifyVideoSize(int32_t width,int32_t height)3509 void AVPlayerNapi::NotifyVideoSize(int32_t width, int32_t height)
3510 {
3511     width_ = width;
3512     height_ = height;
3513 }
3514 
NotifyIsLiveStream()3515 void AVPlayerNapi::NotifyIsLiveStream()
3516 {
3517     isLiveStream_ = true;
3518 }
3519 
NotifyDrmInfoUpdated(const std::multimap<std::string,std::vector<uint8_t>> & infos)3520 void AVPlayerNapi::NotifyDrmInfoUpdated(const std::multimap<std::string, std::vector<uint8_t>> &infos)
3521 {
3522     MEDIA_LOGD("NotifyDrmInfoUpdated");
3523     std::unique_lock<std::shared_mutex> lock(drmMutex_);
3524     for (auto &newItem : infos) {
3525         auto pos = localDrmInfos_.equal_range(newItem.first);
3526         if (pos.first == pos.second && pos.first == localDrmInfos_.end()) {
3527             localDrmInfos_.insert(newItem);
3528             continue;
3529         }
3530         bool isSame = false;
3531         for (; pos.first != pos.second; ++pos.first) {
3532             if (newItem.second == pos.first->second) {
3533                 isSame = true;
3534                 break;
3535             }
3536         }
3537         if (!isSame) {
3538             localDrmInfos_.insert(newItem);
3539         }
3540     }
3541 }
3542 
ResetUserParameters()3543 void AVPlayerNapi::ResetUserParameters()
3544 {
3545     url_.clear();
3546     fileDescriptor_.fd = 0;
3547     fileDescriptor_.offset = 0;
3548     fileDescriptor_.length = -1;
3549     width_ = 0;
3550     height_ = 0;
3551     position_ = -1;
3552     duration_ = -1;
3553     loop_ = false;
3554 }
3555 
StartListenCurrentResource()3556 void AVPlayerNapi::StartListenCurrentResource()
3557 {
3558     std::lock_guard<std::mutex> lock(mutex_);
3559     if (playerCb_ != nullptr) {
3560         playerCb_->Start();
3561     }
3562 }
3563 
PauseListenCurrentResource()3564 void AVPlayerNapi::PauseListenCurrentResource()
3565 {
3566     std::lock_guard<std::mutex> lock(mutex_);
3567     if (playerCb_ != nullptr) {
3568         playerCb_->Pause();
3569     }
3570 }
3571 
3572 /**
3573  * DO NOT hold taskMutex_ before call this function
3574  * AVPlayerCallback::OnErrorCb() hold AVPlayerCallback::mutex_ and wait taskMutex_, may cause dead lock
3575 */
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)3576 void AVPlayerNapi::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
3577 {
3578     std::lock_guard<std::mutex> lock(mutex_);
3579     if (playerCb_ != nullptr) {
3580         playerCb_->OnErrorCb(errorCode, errorMsg);
3581     }
3582 }
3583 
GetJsInstance(napi_env env,napi_callback_info info)3584 AVPlayerNapi* AVPlayerNapi::GetJsInstance(napi_env env, napi_callback_info info)
3585 {
3586     size_t argCount = 0;
3587     napi_value jsThis = nullptr;
3588     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
3589     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
3590 
3591     AVPlayerNapi *jsPlayer = nullptr;
3592     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
3593     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
3594 
3595     return jsPlayer;
3596 }
3597 
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)3598 AVPlayerNapi* AVPlayerNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
3599     size_t &argc, napi_value *argv)
3600 {
3601     napi_value jsThis = nullptr;
3602     napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
3603     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
3604 
3605     AVPlayerNapi *jsPlayer = nullptr;
3606     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
3607     CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
3608 
3609     return jsPlayer;
3610 }
3611 
IsLiveSource() const3612 bool AVPlayerNapi::IsLiveSource() const
3613 {
3614     return isLiveStream_;
3615 }
3616 
GetJsApiVersion()3617 int32_t AVPlayerNapi::GetJsApiVersion()
3618 {
3619     if (player_ != nullptr && getApiVersionFlag_) {
3620         getApiVersionFlag_ = false;
3621         player_->GetApiVersion(g_apiVersion);
3622         MEDIA_LOGI("apiVersion is: %{public}d", g_apiVersion);
3623     }
3624     return g_apiVersion;
3625 }
3626 
AddMediaStreamToAVMediaSource(const std::shared_ptr<AVMediaSourceTmp> & srcTmp,std::shared_ptr<AVMediaSource> & mediaSource)3627 void AVPlayerNapi::AddMediaStreamToAVMediaSource(
3628     const std::shared_ptr<AVMediaSourceTmp> &srcTmp, std::shared_ptr<AVMediaSource> &mediaSource)
3629 {
3630     for (const auto &mediaStreamTmp : srcTmp->getAVPlayMediaStreamTmpList()) {
3631         AVPlayMediaStream mediaStream;
3632         mediaStream.url = mediaStreamTmp.url;
3633         mediaStream.width = mediaStreamTmp.width;
3634         mediaStream.height = mediaStreamTmp.height;
3635         mediaStream.bitrate = mediaStreamTmp.bitrate;
3636         mediaSource->AddMediaStream(mediaStream);
3637     }
3638 }
3639 
JsIsSeekContinuousSupported(napi_env env,napi_callback_info info)3640 napi_value AVPlayerNapi::JsIsSeekContinuousSupported(napi_env env, napi_callback_info info)
3641 {
3642     MediaTrace trace("AVPlayerNapi::isSeekContinuousSupported");
3643     MEDIA_LOGI("JsIsSeekContinuousSupported In");
3644     napi_value result = nullptr;
3645     bool isSeekContinuousSupported = false;
3646     napi_status status = napi_get_boolean(env, isSeekContinuousSupported, &result);
3647     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_boolean failed");
3648     size_t argCount = 0;
3649     AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, nullptr);
3650     CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
3651     if (jsPlayer->isReadyReleased_.load()) {
3652         status = napi_get_boolean(env, false, &result);
3653         CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_boolean failed");
3654         return result;
3655     }
3656     if (jsPlayer->player_ != nullptr) {
3657         isSeekContinuousSupported = jsPlayer->player_->IsSeekContinuousSupported();
3658         status = napi_get_boolean(env, isSeekContinuousSupported, &result);
3659         CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_boolean failed");
3660     }
3661     return result;
3662 }
3663 } // namespace Media
3664 } // namespace OHOS