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