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