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("setPlaybackStrategy", JsSetPlaybackStrategy),
102 DECLARE_NAPI_FUNCTION("setMediaMuted", JsSetMediaMuted),
103 DECLARE_NAPI_FUNCTION("getPlaybackInfo", JsGetPlaybackInfo),
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_LOGI("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 Current 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 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1692 MEDIA_LOGI("SetDataSrc Task");
1693 if (jsPlayer->player_ != nullptr) {
1694 if (jsPlayer->player_->SetSource(jsPlayer->dataSrcCb_) != MSERR_OK) {
1695 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource DataSrc failed");
1696 }
1697 if (jsPlayer->dataSrcDescriptor_.fileSize == -1) {
1698 jsPlayer->isLiveStream_ = true;
1699 }
1700 }
1701 });
1702 (void)jsPlayer->taskQue_->EnqueueTask(task);
1703
1704 MEDIA_LOGI("JsSetDataSrc Out");
1705 return result;
1706 }
1707
JsGetDataSrc(napi_env env,napi_callback_info info)1708 napi_value AVPlayerNapi::JsGetDataSrc(napi_env env, napi_callback_info info)
1709 {
1710 MediaTrace trace("AVPlayerNapi::get dataSrc");
1711 napi_value result = nullptr;
1712 napi_get_undefined(env, &result);
1713 MEDIA_LOGI("JsGetDataSrc In");
1714
1715 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1716 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1717 CHECK_AND_RETURN_RET_LOG(jsPlayer->dataSrcCb_ != nullptr, result, "failed to check dataSrcCb_");
1718
1719 napi_value value = nullptr;
1720 int64_t fileSize;
1721 napi_value callback = nullptr;
1722 (void)napi_create_object(env, &value);
1723 (void)jsPlayer->dataSrcCb_->GetSize(fileSize);
1724 (void)CommonNapi::AddNumberPropInt64(env, value, "fileSize", fileSize);
1725 int32_t ret = jsPlayer->dataSrcCb_->GetCallback(READAT_CALLBACK_NAME, &callback);
1726 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, result, "failed to GetCallback");
1727 (void)MediaDataSourceCallback::AddNapiValueProp(env, value, "callback", callback);
1728
1729 MEDIA_LOGI("JsGetDataSrc Out");
1730 return value;
1731 }
1732
1733 #ifdef SUPPORT_VIDEO
SetSurface(const std::string & surfaceStr)1734 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
1735 {
1736 MEDIA_LOGI("get surface, surfaceStr = %{public}s", surfaceStr.c_str());
1737 uint64_t surfaceId = 0;
1738 if (surfaceStr.empty() || surfaceStr[0] < '0' || surfaceStr[0] > '9') {
1739 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1740 "Please obtain the surface from XComponentController.getXComponentSurfaceId");
1741 return;
1742 }
1743 surfaceId = std::stoull(surfaceStr);
1744 MEDIA_LOGI("get surface, surfaceId = (%{public}" PRIu64 ")", surfaceId);
1745
1746 auto surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
1747 if (surface == nullptr) {
1748 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SurfaceUtils cannot convert ID to Surface");
1749 return;
1750 }
1751
1752 auto task = std::make_shared<TaskHandler<void>>([this, surface]() {
1753 MEDIA_LOGI("0x%{public}06" PRIXPTR " SetSurface Task", FAKE_POINTER(this));
1754 if (player_ != nullptr) {
1755 (void)player_->SetVideoSurface(surface);
1756 }
1757 });
1758 (void)taskQue_->EnqueueTask(task);
1759 }
1760 #else
SetSurface(const std::string & surfaceStr)1761 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
1762 {
1763 (void)surfaceStr;
1764 OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The music player does not need to support (Surface)");
1765 }
1766 #endif
1767
JsSetSurfaceID(napi_env env,napi_callback_info info)1768 napi_value AVPlayerNapi::JsSetSurfaceID(napi_env env, napi_callback_info info)
1769 {
1770 MediaTrace trace("AVPlayerNapi::set surface");
1771 napi_value result = nullptr;
1772 napi_get_undefined(env, &result);
1773 MEDIA_LOGD("JsSetSurfaceID In");
1774
1775 napi_value args[1] = { nullptr };
1776 size_t argCount = 1; // surfaceId?: string
1777 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1778 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1779
1780 napi_valuetype valueType = napi_undefined;
1781 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1782 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "the attribute(SurfaceID) input is not string");
1783 return result;
1784 }
1785
1786 std::string curState = jsPlayer->GetCurrentState();
1787 bool setSurfaceFirst = curState == AVPlayerState::STATE_INITIALIZED;
1788 bool switchSurface = curState == AVPlayerState::STATE_PREPARED ||
1789 curState == AVPlayerState::STATE_PLAYING ||
1790 curState == AVPlayerState::STATE_PAUSED ||
1791 curState == AVPlayerState::STATE_STOPPED ||
1792 curState == AVPlayerState::STATE_COMPLETED;
1793
1794 if (setSurfaceFirst) {
1795 MEDIA_LOGI("JsSetSurfaceID set surface first in %{public}s state", curState.c_str());
1796 } else if (switchSurface) {
1797 MEDIA_LOGI("JsSetSurfaceID switch surface in %{public}s state", curState.c_str());
1798 std::string oldSurface = jsPlayer->surface_;
1799 if (oldSurface.empty()) {
1800 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1801 "switch surface with no old surface");
1802 return result;
1803 }
1804 } else {
1805 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1806 "the attribute(SurfaceID) can only be set in the initialized state");
1807 return result;
1808 }
1809
1810 // get url from js
1811 jsPlayer->surface_ = CommonNapi::GetStringArgument(env, args[0]);
1812 jsPlayer->SetSurface(jsPlayer->surface_);
1813 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetSurfaceID Out", FAKE_POINTER(jsPlayer));
1814 return result;
1815 }
1816
JsGetSurfaceID(napi_env env,napi_callback_info info)1817 napi_value AVPlayerNapi::JsGetSurfaceID(napi_env env, napi_callback_info info)
1818 {
1819 MediaTrace trace("AVPlayerNapi::get surface");
1820 napi_value result = nullptr;
1821 napi_get_undefined(env, &result);
1822 MEDIA_LOGD("JsGetSurfaceID In");
1823
1824 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1825 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1826
1827 napi_value value = nullptr;
1828 (void)napi_create_string_utf8(env, jsPlayer->surface_.c_str(), NAPI_AUTO_LENGTH, &value);
1829
1830 MEDIA_LOGI("JsGetSurfaceID Out Current SurfaceID: %{public}s", jsPlayer->surface_.c_str());
1831 return value;
1832 }
1833
JsSetLoop(napi_env env,napi_callback_info info)1834 napi_value AVPlayerNapi::JsSetLoop(napi_env env, napi_callback_info info)
1835 {
1836 MediaTrace trace("AVPlayerNapi::set loop");
1837 napi_value result = nullptr;
1838 napi_get_undefined(env, &result);
1839 MEDIA_LOGI("JsSetLoop In");
1840
1841 napi_value args[1] = { nullptr };
1842 size_t argCount = 1; // loop: boolenan
1843 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1844 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1845
1846 if (jsPlayer->IsLiveSource()) {
1847 jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support loop");
1848 return result;
1849 }
1850
1851 if (!jsPlayer->IsControllable()) {
1852 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1853 "current state is not prepared/playing/paused/completed, unsupport loop operation");
1854 return result;
1855 }
1856
1857 napi_valuetype valueType = napi_undefined;
1858 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
1859 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetLoop is not napi_boolean");
1860 return result;
1861 }
1862
1863 napi_status status = napi_get_value_bool(env, args[0], &jsPlayer->loop_);
1864 if (status != napi_ok) {
1865 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1866 "invalid parameters, please check the input loop");
1867 return result;
1868 }
1869
1870 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1871 MEDIA_LOGD("SetLooping Task");
1872 if (jsPlayer->player_ != nullptr) {
1873 (void)jsPlayer->player_->SetLooping(jsPlayer->loop_);
1874 }
1875 });
1876 (void)jsPlayer->taskQue_->EnqueueTask(task);
1877 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetLoop Out", FAKE_POINTER(jsPlayer));
1878 return result;
1879 }
1880
JsGetLoop(napi_env env,napi_callback_info info)1881 napi_value AVPlayerNapi::JsGetLoop(napi_env env, napi_callback_info info)
1882 {
1883 MediaTrace trace("AVPlayerNapi::get loop");
1884 napi_value result = nullptr;
1885 napi_get_undefined(env, &result);
1886 MEDIA_LOGI("JsGetLoop In");
1887
1888 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1889 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1890
1891 napi_value value = nullptr;
1892 (void)napi_get_boolean(env, jsPlayer->loop_, &value);
1893 MEDIA_LOGI("JsGetLoop Out Current Loop: %{public}d", jsPlayer->loop_);
1894 return value;
1895 }
1896
JsSetVideoScaleType(napi_env env,napi_callback_info info)1897 napi_value AVPlayerNapi::JsSetVideoScaleType(napi_env env, napi_callback_info info)
1898 {
1899 MediaTrace trace("AVPlayerNapi::set videoScaleType");
1900 napi_value result = nullptr;
1901 napi_get_undefined(env, &result);
1902 MEDIA_LOGI("JsSetVideoScaleType In");
1903
1904 napi_value args[1] = { nullptr };
1905 size_t argCount = 1;
1906 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1907 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1908
1909 if (!jsPlayer->IsControllable()) {
1910 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1911 "current state is not prepared/playing/paused/completed, unsupport video scale operation");
1912 return result;
1913 }
1914
1915 napi_valuetype valueType = napi_undefined;
1916 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1917 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetVideoScaleType is not napi_number");
1918 return result;
1919 }
1920
1921 int32_t videoScaleType = 0;
1922 napi_status status = napi_get_value_int32(env, args[0], &videoScaleType);
1923 if (status != napi_ok || videoScaleType < static_cast<int32_t>(Plugins::VideoScaleType::VIDEO_SCALE_TYPE_FIT)
1924 || videoScaleType > static_cast<int32_t>(Plugins::VideoScaleType::VIDEO_SCALE_TYPE_FIT_CROP)) {
1925 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input scale type");
1926 return result;
1927 }
1928 jsPlayer->videoScaleType_ = videoScaleType;
1929
1930 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, videoScaleType]() {
1931 MEDIA_LOGI("SetVideoScaleType Task");
1932 if (jsPlayer->player_ != nullptr) {
1933 Format format;
1934 (void)format.PutIntValue(PlayerKeys::VIDEO_SCALE_TYPE, videoScaleType);
1935 (void)jsPlayer->player_->SetParameter(format);
1936 }
1937 });
1938 (void)jsPlayer->taskQue_->EnqueueTask(task);
1939 MEDIA_LOGI("JsSetVideoScaleType Out");
1940 return result;
1941 }
1942
JsGetVideoScaleType(napi_env env,napi_callback_info info)1943 napi_value AVPlayerNapi::JsGetVideoScaleType(napi_env env, napi_callback_info info)
1944 {
1945 MediaTrace trace("AVPlayerNapi::get videoScaleType");
1946 napi_value result = nullptr;
1947 napi_get_undefined(env, &result);
1948 MEDIA_LOGI("JsGetVideoScaleType In");
1949
1950 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1951 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1952
1953 napi_value value = nullptr;
1954 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->videoScaleType_), &value);
1955 MEDIA_LOGI("JsGetVideoScaleType Out Current VideoScale: %{public}d", jsPlayer->videoScaleType_);
1956 return value;
1957 }
1958
JsSetAudioInterruptMode(napi_env env,napi_callback_info info)1959 napi_value AVPlayerNapi::JsSetAudioInterruptMode(napi_env env, napi_callback_info info)
1960 {
1961 MediaTrace trace("AVPlayerNapi::set audioInterruptMode");
1962 napi_value result = nullptr;
1963 napi_get_undefined(env, &result);
1964 MEDIA_LOGI("JsSetAudioInterruptMode In");
1965
1966 napi_value args[1] = { nullptr };
1967 size_t argCount = 1;
1968 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1969 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1970
1971 if (!jsPlayer->IsControllable()) {
1972 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1973 "current state is not prepared/playing/paused/completed, unsupport audio interrupt operation");
1974 return result;
1975 }
1976
1977 napi_valuetype valueType = napi_undefined;
1978 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1979 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAudioInterruptMode is not napi_number");
1980 return result;
1981 }
1982
1983 int32_t interruptMode = 0;
1984 napi_status status = napi_get_value_int32(env, args[0], &interruptMode);
1985 if (status != napi_ok ||
1986 interruptMode < AudioStandard::InterruptMode::SHARE_MODE ||
1987 interruptMode > AudioStandard::InterruptMode::INDEPENDENT_MODE) {
1988 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1989 "invalid parameters, please check the input interrupt Mode");
1990 return result;
1991 }
1992 jsPlayer->interruptMode_ = static_cast<AudioStandard::InterruptMode>(interruptMode);
1993
1994 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1995 MEDIA_LOGI("SetAudioInterruptMode Task");
1996 if (jsPlayer->player_ != nullptr) {
1997 Format format;
1998 (void)format.PutIntValue(PlayerKeys::AUDIO_INTERRUPT_MODE, jsPlayer->interruptMode_);
1999 (void)jsPlayer->player_->SetParameter(format);
2000 }
2001 });
2002 (void)jsPlayer->taskQue_->EnqueueTask(task);
2003 MEDIA_LOGI("JsSetAudioInterruptMode Out");
2004 return result;
2005 }
2006
JsGetAudioInterruptMode(napi_env env,napi_callback_info info)2007 napi_value AVPlayerNapi::JsGetAudioInterruptMode(napi_env env, napi_callback_info info)
2008 {
2009 MediaTrace trace("AVPlayerNapi::get audioInterruptMode");
2010 napi_value result = nullptr;
2011 napi_get_undefined(env, &result);
2012 MEDIA_LOGI("JsGetAudioInterruptMode In");
2013
2014 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2015 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2016
2017 napi_value value = nullptr;
2018 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->interruptMode_), &value);
2019 MEDIA_LOGI("JsGetAudioInterruptMode Out");
2020 return value;
2021 }
2022
JsSetAudioEffectMode(napi_env env,napi_callback_info info)2023 napi_value AVPlayerNapi::JsSetAudioEffectMode(napi_env env, napi_callback_info info)
2024 {
2025 MediaTrace trace("AVPlayerNapi::JsSetAudioEffectMode");
2026 MEDIA_LOGI("JsSetAudioEffectMode In");
2027 napi_value result = nullptr;
2028 napi_get_undefined(env, &result);
2029
2030 size_t argCount = 1; // 1param audioEffectMode
2031 napi_value args[1] = { nullptr };
2032 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2033 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2034
2035 if (!jsPlayer->IsControllable()) {
2036 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2037 "current state is not prepared/playing/paused/completed, unsupport audio effect mode operation");
2038 return result;
2039 }
2040
2041 napi_valuetype valueType = napi_undefined;
2042 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
2043 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "audioEffectMode is not number");
2044 return result;
2045 }
2046
2047 int32_t effectMode = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
2048 napi_status status = napi_get_value_int32(env, args[0], &effectMode);
2049 if (status != napi_ok || effectMode > OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT ||
2050 effectMode < OHOS::AudioStandard::AudioEffectMode::EFFECT_NONE) {
2051 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2052 "invalid audioEffectMode, please check the input audio effect Mode");
2053 return result;
2054 }
2055
2056 if (jsPlayer->audioEffectMode_ == effectMode) {
2057 MEDIA_LOGI("Same effectMode parameter");
2058 return result;
2059 }
2060
2061 jsPlayer->audioEffectMode_ = effectMode;
2062
2063 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, effectMode]() {
2064 MEDIA_LOGI("JsSetAudioEffectMode Task in");
2065 if (jsPlayer->player_ != nullptr) {
2066 Format format;
2067 (void)format.PutIntValue(PlayerKeys::AUDIO_EFFECT_MODE, effectMode);
2068 (void)jsPlayer->player_->SetParameter(format);
2069 }
2070 MEDIA_LOGI("JsSetAudioEffectMode Task out");
2071 });
2072 (void)jsPlayer->taskQue_->EnqueueTask(task);
2073 MEDIA_LOGI("JsSetAudioEffectMode Out");
2074 return result;
2075 }
2076
JsGetAudioEffectMode(napi_env env,napi_callback_info info)2077 napi_value AVPlayerNapi::JsGetAudioEffectMode(napi_env env, napi_callback_info info)
2078 {
2079 MediaTrace trace("AVPlayerNapi::JsGetAudioEffectMode");
2080 MEDIA_LOGI("JsGetAudioEffectMode In");
2081 napi_value result = nullptr;
2082 napi_get_undefined(env, &result);
2083
2084 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2085 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2086
2087 napi_value value = nullptr;
2088 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->audioEffectMode_), &value);
2089 MEDIA_LOGI("JsGetAudioEffectMode Out");
2090 return value;
2091 }
2092
JsHandleParameter(napi_env env,napi_value args,AVPlayerNapi * jsPlayer)2093 bool AVPlayerNapi::JsHandleParameter(napi_env env, napi_value args, AVPlayerNapi *jsPlayer)
2094 {
2095 int32_t content = CONTENT_TYPE_UNKNOWN;
2096 int32_t usage = -1;
2097 int32_t rendererFlags = -1;
2098 (void)CommonNapi::GetPropertyInt32(env, args, "content", content);
2099 (void)CommonNapi::GetPropertyInt32(env, args, "usage", usage);
2100 (void)CommonNapi::GetPropertyInt32(env, args, "rendererFlags", rendererFlags);
2101 MEDIA_LOGI("content = %{public}d, usage = %{public}d, rendererFlags = %{public}d",
2102 content, usage, rendererFlags);
2103 std::vector<int32_t> contents = {
2104 CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_SPEECH,
2105 CONTENT_TYPE_MUSIC, CONTENT_TYPE_MOVIE,
2106 CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_RINGTONE
2107 };
2108 std::vector<int32_t> usages = {
2109 STREAM_USAGE_UNKNOWN, STREAM_USAGE_MEDIA,
2110 STREAM_USAGE_MUSIC, STREAM_USAGE_VOICE_COMMUNICATION,
2111 STREAM_USAGE_VOICE_ASSISTANT, STREAM_USAGE_ALARM,
2112 STREAM_USAGE_VOICE_MESSAGE, STREAM_USAGE_NOTIFICATION_RINGTONE,
2113 STREAM_USAGE_RINGTONE, STREAM_USAGE_NOTIFICATION,
2114 STREAM_USAGE_ACCESSIBILITY, STREAM_USAGE_SYSTEM,
2115 STREAM_USAGE_MOVIE, STREAM_USAGE_GAME,
2116 STREAM_USAGE_AUDIOBOOK, STREAM_USAGE_NAVIGATION,
2117 STREAM_USAGE_DTMF, STREAM_USAGE_ENFORCED_TONE,
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
SelectTrackEnqueueTask(AVPlayerNapi * jsPlayer,int32_t index,int32_t mode)2152 void AVPlayerNapi::SelectTrackEnqueueTask(AVPlayerNapi *jsPlayer, int32_t index, int32_t mode)
2153 {
2154 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, index, mode]() {
2155 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Task In", FAKE_POINTER(jsPlayer));
2156 if (jsPlayer->player_ != nullptr) {
2157 (void)jsPlayer->player_->SelectTrack(index, jsPlayer->TransferSwitchMode(mode));
2158 }
2159 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Task Out", FAKE_POINTER(jsPlayer));
2160 });
2161 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack EnqueueTask In", FAKE_POINTER(jsPlayer));
2162 (void)jsPlayer->taskQue_->EnqueueTask(task);
2163 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSelectTrack Out", FAKE_POINTER(jsPlayer));
2164 }
2165
JsSetAudioRendererInfo(napi_env env,napi_callback_info info)2166 napi_value AVPlayerNapi::JsSetAudioRendererInfo(napi_env env, napi_callback_info info)
2167 {
2168 MediaTrace trace("AVPlayerNapi::set audioRendererInfo");
2169 napi_value result = nullptr;
2170 napi_get_undefined(env, &result);
2171 MEDIA_LOGI("JsSetAudioRendererInfo In");
2172
2173 napi_value args[1] = { nullptr };
2174 size_t argCount = 1;
2175 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2176 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2177 napi_valuetype valueType = napi_undefined;
2178 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
2179 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input");
2180 return result;
2181 }
2182 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_INITIALIZED) {
2183 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2184 "current state is not initialized, unsupport to set audio renderer info");
2185 return result;
2186 }
2187 if (!AVPlayerNapi::JsHandleParameter(env, args[0], jsPlayer)) {
2188 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
2189 "invalid parameters, please check the input audio renderer info");
2190 return result;
2191 }
2192 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
2193 MEDIA_LOGI("SetAudioRendererInfo Task");
2194 if (jsPlayer->player_ != nullptr) {
2195 Format format;
2196 (void)format.PutIntValue(PlayerKeys::CONTENT_TYPE, jsPlayer->audioRendererInfo_.contentType);
2197 (void)format.PutIntValue(PlayerKeys::STREAM_USAGE, jsPlayer->audioRendererInfo_.streamUsage);
2198 (void)format.PutIntValue(PlayerKeys::RENDERER_FLAG, jsPlayer->audioRendererInfo_.rendererFlags);
2199 (void)jsPlayer->player_->SetParameter(format);
2200 }
2201 });
2202 (void)jsPlayer->taskQue_->EnqueueTask(task);
2203 MEDIA_LOGI("JsSetAudioRendererInfo Out");
2204 return result;
2205 }
2206
JsGetAudioRendererInfo(napi_env env,napi_callback_info info)2207 napi_value AVPlayerNapi::JsGetAudioRendererInfo(napi_env env, napi_callback_info info)
2208 {
2209 MediaTrace trace("AVPlayerNapi::get audioRendererInfo");
2210 napi_value result = nullptr;
2211 napi_get_undefined(env, &result);
2212 MEDIA_LOGI("JsGetAudioRendererInfo In");
2213
2214 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2215 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2216
2217 int32_t content = static_cast<int32_t>(jsPlayer->audioRendererInfo_.contentType);
2218 int32_t usage = static_cast<int32_t>(jsPlayer->audioRendererInfo_.streamUsage);
2219 int32_t rendererFlags = jsPlayer->audioRendererInfo_.rendererFlags;
2220 (void)napi_create_object(env, &result);
2221 CommonNapi::SetPropertyInt32(env, result, "content", content);
2222 CommonNapi::SetPropertyInt32(env, result, "usage", usage);
2223 CommonNapi::SetPropertyInt32(env, result, "rendererFlags", rendererFlags);
2224 MEDIA_LOGI("JsGetAudioRendererInfo Out");
2225 return result;
2226 }
2227
JsGetCurrentTime(napi_env env,napi_callback_info info)2228 napi_value AVPlayerNapi::JsGetCurrentTime(napi_env env, napi_callback_info info)
2229 {
2230 MediaTrace trace("AVPlayerNapi::get currentTime");
2231 napi_value result = nullptr;
2232 napi_get_undefined(env, &result);
2233 MEDIA_LOGD("JsGetCurrentTime In");
2234
2235 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2236 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2237
2238 int32_t currentTime = -1;
2239 if (jsPlayer->IsControllable()) {
2240 currentTime = jsPlayer->position_;
2241 }
2242
2243 if (jsPlayer->IsLiveSource() && jsPlayer->dataSrcCb_ == nullptr) {
2244 currentTime = -1;
2245 }
2246 napi_value value = nullptr;
2247 (void)napi_create_int32(env, currentTime, &value);
2248 std::string curState = jsPlayer->GetCurrentState();
2249 if (currentTime != -1) {
2250 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsGetCurrenTime Out, state %{public}s, time: %{public}d",
2251 FAKE_POINTER(jsPlayer), curState.c_str(), currentTime);
2252 }
2253 return value;
2254 }
2255
JsGetDuration(napi_env env,napi_callback_info info)2256 napi_value AVPlayerNapi::JsGetDuration(napi_env env, napi_callback_info info)
2257 {
2258 MediaTrace trace("AVPlayerNapi::get duration");
2259 napi_value result = nullptr;
2260 napi_get_undefined(env, &result);
2261 MEDIA_LOGD("JsGetDuration In");
2262
2263 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2264 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2265
2266 int32_t duration = -1;
2267 if (jsPlayer->IsControllable() && !jsPlayer->IsLiveSource()) {
2268 duration = jsPlayer->duration_;
2269 }
2270
2271 napi_value value = nullptr;
2272 (void)napi_create_int32(env, duration, &value);
2273 std::string curState = jsPlayer->GetCurrentState();
2274 MEDIA_LOGD("JsGetDuration Out, state %{public}s, duration %{public}d", curState.c_str(), duration);
2275 return value;
2276 }
2277
IsControllable()2278 bool AVPlayerNapi::IsControllable()
2279 {
2280 auto state = GetCurrentState();
2281 if (state == AVPlayerState::STATE_PREPARED || state == AVPlayerState::STATE_PLAYING ||
2282 state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_COMPLETED) {
2283 return true;
2284 } else {
2285 return false;
2286 }
2287 }
2288
CanSetPlayRange()2289 bool AVPlayerNapi::CanSetPlayRange()
2290 {
2291 auto state = GetCurrentState();
2292 if (state == AVPlayerState::STATE_INITIALIZED || state == AVPlayerState::STATE_PREPARED ||
2293 state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_STOPPED ||
2294 state == AVPlayerState::STATE_COMPLETED) {
2295 return true;
2296 }
2297 return false;
2298 }
2299
GetCurrentState()2300 std::string AVPlayerNapi::GetCurrentState()
2301 {
2302 if (isReleased_.load()) {
2303 return AVPlayerState::STATE_RELEASED;
2304 }
2305
2306 std::string curState = AVPlayerState::STATE_ERROR;
2307 static const std::map<PlayerStates, std::string> stateMap = {
2308 {PLAYER_IDLE, AVPlayerState::STATE_IDLE},
2309 {PLAYER_INITIALIZED, AVPlayerState::STATE_INITIALIZED},
2310 {PLAYER_PREPARED, AVPlayerState::STATE_PREPARED},
2311 {PLAYER_STARTED, AVPlayerState::STATE_PLAYING},
2312 {PLAYER_PAUSED, AVPlayerState::STATE_PAUSED},
2313 {PLAYER_STOPPED, AVPlayerState::STATE_STOPPED},
2314 {PLAYER_PLAYBACK_COMPLETE, AVPlayerState::STATE_COMPLETED},
2315 {PLAYER_STATE_ERROR, AVPlayerState::STATE_ERROR},
2316 };
2317
2318 if (stateMap.find(state_) != stateMap.end()) {
2319 curState = stateMap.at(state_);
2320 }
2321 return curState;
2322 }
2323
JsGetState(napi_env env,napi_callback_info info)2324 napi_value AVPlayerNapi::JsGetState(napi_env env, napi_callback_info info)
2325 {
2326 MediaTrace trace("AVPlayerNapi::get state");
2327 napi_value result = nullptr;
2328 napi_get_undefined(env, &result);
2329 MEDIA_LOGD("JsGetState In");
2330
2331 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2332 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2333
2334 std::string curState = jsPlayer->GetCurrentState();
2335 napi_value value = nullptr;
2336 (void)napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &value);
2337 MEDIA_LOGD("JsGetState Out");
2338 return value;
2339 }
2340
JsGetWidth(napi_env env,napi_callback_info info)2341 napi_value AVPlayerNapi::JsGetWidth(napi_env env, napi_callback_info info)
2342 {
2343 MediaTrace trace("AVPlayerNapi::get width");
2344 napi_value result = nullptr;
2345 napi_get_undefined(env, &result);
2346 MEDIA_LOGI("JsGetWidth");
2347
2348 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2349 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2350
2351 int32_t width = 0;
2352 if (jsPlayer->IsControllable()) {
2353 width = jsPlayer->width_;
2354 }
2355
2356 napi_value value = nullptr;
2357 (void)napi_create_int32(env, width, &value);
2358 return value;
2359 }
2360
JsGetHeight(napi_env env,napi_callback_info info)2361 napi_value AVPlayerNapi::JsGetHeight(napi_env env, napi_callback_info info)
2362 {
2363 MediaTrace trace("AVPlayerNapi::get height");
2364 napi_value result = nullptr;
2365 napi_get_undefined(env, &result);
2366 MEDIA_LOGI("JsGetHeight");
2367
2368 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
2369 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2370
2371 int32_t height = 0;
2372 if (jsPlayer->IsControllable()) {
2373 height = jsPlayer->height_;
2374 }
2375
2376 napi_value value = nullptr;
2377 (void)napi_create_int32(env, height, &value);
2378 return value;
2379 }
2380
JsGetTrackDescription(napi_env env,napi_callback_info info)2381 napi_value AVPlayerNapi::JsGetTrackDescription(napi_env env, napi_callback_info info)
2382 {
2383 MediaTrace trace("AVPlayerNapi::get trackDescription");
2384 napi_value result = nullptr;
2385 napi_get_undefined(env, &result);
2386 MEDIA_LOGI("GetTrackDescription In");
2387
2388 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
2389 napi_value args[1] = { nullptr };
2390 size_t argCount = 1;
2391 promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2392 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
2393 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
2394
2395 auto jsPlayer = promiseCtx->napi;
2396 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
2397 MEDIA_LOGD("0x%{public}06" PRIXPTR " JsGetTrackDescription EnqueueTask In", FAKE_POINTER(jsPlayer));
2398 promiseCtx->asyncTask = jsPlayer->GetTrackDescriptionTask(promiseCtx);
2399 MEDIA_LOGD("0x%{public}06" PRIXPTR " JsGetTrackDescription EnqueueTask Out", FAKE_POINTER(jsPlayer));
2400
2401 // async work
2402 napi_value resource = nullptr;
2403 napi_create_string_utf8(env, "JsGetTrackDescription", NAPI_AUTO_LENGTH, &resource);
2404 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
2405 [](napi_env env, void *data) {
2406 MEDIA_LOGI("Wait JsGetTrackDescription Task Start");
2407 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
2408 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
2409 if (promiseCtx->asyncTask) {
2410 auto result = promiseCtx->asyncTask->GetResult();
2411 if (!result.HasResult()) {
2412 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2413 "task has been cleared");
2414 }
2415 if (result.Value().first != MSERR_EXT_API9_OK) {
2416 return promiseCtx->SignError(result.Value().first, result.Value().second);
2417 }
2418 promiseCtx->JsResult = std::make_unique<MediaJsResultArray>(promiseCtx->trackInfoVec_);
2419 }
2420 MEDIA_LOGI("Wait JsGetTrackDescription Task End");
2421 },
2422 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
2423 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
2424 promiseCtx.release();
2425 MEDIA_LOGI("GetTrackDescription Out");
2426 return result;
2427 }
2428
GetTrackDescriptionTask(const std::unique_ptr<AVPlayerContext> & promiseCtx)2429 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::GetTrackDescriptionTask(const std::unique_ptr<AVPlayerContext>
2430 &promiseCtx)
2431 {
2432 auto task = std::make_shared<TaskHandler<TaskRet>>([this, &trackInfo = promiseCtx->trackInfoVec_]() {
2433 MEDIA_LOGI("0x%{public}06" PRIXPTR " GetTrackDescription Task In", FAKE_POINTER(this));
2434 std::unique_lock<std::mutex> lock(taskMutex_);
2435 trackInfo.clear();
2436 if (IsControllable()) {
2437 (void)player_->GetVideoTrackInfo(trackInfo);
2438 (void)player_->GetAudioTrackInfo(trackInfo);
2439 (void)player_->GetSubtitleTrackInfo(trackInfo);
2440 } else {
2441 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2442 "current state unsupport get track description");
2443 }
2444 MEDIA_LOGI("0x%{public}06" PRIXPTR " GetTrackDescription Task Out", FAKE_POINTER(this));
2445 return TaskRet(MSERR_EXT_API9_OK, "Success");
2446 });
2447 (void)taskQue_->EnqueueTask(task);
2448 return task;
2449 }
2450
JsGetSelectedTracks(napi_env env,napi_callback_info info)2451 napi_value AVPlayerNapi::JsGetSelectedTracks(napi_env env, napi_callback_info info)
2452 {
2453 MediaTrace trace("AVPlayerNapi::get selected tracks");
2454 napi_value result = nullptr;
2455 napi_get_undefined(env, &result);
2456 MEDIA_LOGI("JsGetSelectedTracks In");
2457
2458 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
2459 napi_value args[1] = { nullptr };
2460 size_t argCount = 1;
2461 promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2462 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
2463 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
2464 // async work
2465 napi_value resource = nullptr;
2466 napi_create_string_utf8(env, "JsGetSelectedTracks ", NAPI_AUTO_LENGTH, &resource);
2467 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
2468 MEDIA_LOGI("JsGetSelectedTracks Task");
2469 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
2470 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
2471
2472 auto jsPlayer = promiseCtx->napi;
2473 if (jsPlayer == nullptr) {
2474 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
2475 }
2476
2477 std::vector<int32_t> trackIndex;
2478 if (jsPlayer->IsControllable()) {
2479 int32_t videoIndex = -1;
2480 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_VID, videoIndex);
2481 if (videoIndex != -1) {
2482 trackIndex.push_back(videoIndex);
2483 }
2484
2485 int32_t audioIndex = -1;
2486 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_AUD, audioIndex);
2487 if (audioIndex != -1) {
2488 trackIndex.push_back(audioIndex);
2489 }
2490
2491 int32_t subtitleIndex = -1;
2492 (void)jsPlayer->player_->GetCurrentTrack(MediaType::MEDIA_TYPE_SUBTITLE, subtitleIndex);
2493 if (subtitleIndex != -1) {
2494 trackIndex.push_back(subtitleIndex);
2495 }
2496 } else {
2497 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2498 "current state unsupport get current selections");
2499 }
2500 promiseCtx->JsResult = std::make_unique<MediaJsResultIntArray>(trackIndex);
2501 },
2502 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
2503 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
2504 promiseCtx.release();
2505 MEDIA_LOGI("JsGetSelectedTracks Out");
2506 return result;
2507 }
2508
JsSelectTrack(napi_env env,napi_callback_info info)2509 napi_value AVPlayerNapi::JsSelectTrack(napi_env env, napi_callback_info info)
2510 {
2511 MediaTrace trace("AVPlayerNapi::selectTrack");
2512 MEDIA_LOGI("JsSelectTrack In");
2513 napi_value ret = nullptr;
2514 napi_get_undefined(env, &ret);
2515
2516 size_t argCount = 2; // 2 prarm, args[0]:index args[1]:SwitchMode
2517 napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr };
2518 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2519 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, ret, "failed to GetJsInstanceWithParameter");
2520
2521 napi_valuetype valueType = napi_undefined;
2522 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
2523 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
2524 return ret;
2525 }
2526 int32_t index = -1;
2527 napi_status status = napi_get_value_int32(env, args[0], &index);
2528 if (status != napi_ok || index < 0) {
2529 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the track index");
2530 return ret;
2531 }
2532 int32_t mode = SWITCH_SMOOTH;
2533 if (argCount > 1) {
2534 if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
2535 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "switch mode is not number");
2536 return ret;
2537 }
2538 status = napi_get_value_int32(env, args[1], &mode);
2539 if (status != napi_ok || mode < SWITCH_SMOOTH || mode > SWITCH_CLOSEST) {
2540 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please switch seek mode");
2541 return ret;
2542 }
2543 }
2544 if (!jsPlayer->IsControllable()) {
2545 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2546 "current state is not prepared/playing/paused/completed, unsupport selectTrack operation");
2547 return ret;
2548 }
2549 SelectTrackEnqueueTask(jsPlayer, index, mode);
2550 MEDIA_LOGI("JsSelectTrack Out");
2551 return ret;
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
DeviceChangeCallbackOn(AVPlayerNapi * jsPlayer,std::string callbackName)2677 void AVPlayerNapi::DeviceChangeCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName)
2678 {
2679 if (jsPlayer == nullptr) {
2680 deviceChangeCallbackflag_ = false;
2681 return;
2682 }
2683 if (callbackName == "audioOutputDeviceChangeWithInfo") {
2684 deviceChangeCallbackflag_ = true;
2685 }
2686 if (jsPlayer->player_ != nullptr && deviceChangeCallbackflag_) {
2687 (void)jsPlayer->player_->SetDeviceChangeCbStatus(deviceChangeCallbackflag_);
2688 }
2689 }
2690
DeviceChangeCallbackOff(AVPlayerNapi * jsPlayer,std::string callbackName)2691 void AVPlayerNapi::DeviceChangeCallbackOff(AVPlayerNapi *jsPlayer, std::string callbackName)
2692 {
2693 if (jsPlayer != nullptr && deviceChangeCallbackflag_ && callbackName == "audioOutputDeviceChangeWithInfo") {
2694 deviceChangeCallbackflag_ = false;
2695 if (jsPlayer->player_ != nullptr) {
2696 (void)jsPlayer->player_->SetDeviceChangeCbStatus(deviceChangeCallbackflag_);
2697 }
2698 }
2699 }
MaxAmplitudeCallbackOn(AVPlayerNapi * jsPlayer,std::string callbackName)2700 void AVPlayerNapi::MaxAmplitudeCallbackOn(AVPlayerNapi *jsPlayer, std::string callbackName)
2701 {
2702 if (jsPlayer == nullptr) {
2703 calMaxAmplitude_ = false;
2704 return;
2705 }
2706 if (callbackName == "amplitudeUpdate") {
2707 calMaxAmplitude_ = true;
2708 }
2709 if (jsPlayer->player_ != nullptr && calMaxAmplitude_) {
2710 (void)jsPlayer->player_->SetMaxAmplitudeCbStatus(calMaxAmplitude_);
2711 }
2712 }
2713
JsSetOnCallback(napi_env env,napi_callback_info info)2714 napi_value AVPlayerNapi::JsSetOnCallback(napi_env env, napi_callback_info info)
2715 {
2716 MediaTrace trace("AVPlayerNapi::on");
2717 napi_value result = nullptr;
2718 napi_get_undefined(env, &result);
2719 MEDIA_LOGD("JsSetOnCallback In");
2720
2721 constexpr size_t requireArgc = 2;
2722 napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr }; // args[0]:type, args[1]:callback
2723 size_t argCount = 2; // args[0]:type, args[1]:callback
2724 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2725 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2726
2727 if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
2728 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to on event");
2729 return result;
2730 }
2731
2732 napi_valuetype valueType0 = napi_undefined;
2733 napi_valuetype valueType1 = napi_undefined;
2734 if (argCount < requireArgc) {
2735 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Mandatory parameters are left unspecified.");
2736 return result;
2737 }
2738
2739 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
2740 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "type should be string.");
2741 return result;
2742 }
2743
2744 if (napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
2745 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "callback type should be Callback or function.");
2746 return result;
2747 }
2748
2749 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
2750 jsPlayer->MaxAmplitudeCallbackOn(jsPlayer, callbackName);
2751 MEDIA_LOGI("0x%{public}06" PRIXPTR " set callbackName: %{public}s", FAKE_POINTER(jsPlayer), callbackName.c_str());
2752
2753 napi_ref ref = nullptr;
2754 napi_status status = napi_create_reference(env, args[1], 1, &ref);
2755 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
2756
2757 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
2758 jsPlayer->SaveCallbackReference(callbackName, autoRef);
2759
2760 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsSetOnCallback callbackName: %{public}s success",
2761 FAKE_POINTER(jsPlayer), callbackName.c_str());
2762 return result;
2763 }
2764
MaxAmplitudeCallbackOff(AVPlayerNapi * jsPlayer,std::string callbackName)2765 void AVPlayerNapi::MaxAmplitudeCallbackOff(AVPlayerNapi *jsPlayer, std::string callbackName)
2766 {
2767 if (jsPlayer != nullptr && calMaxAmplitude_ && callbackName == "amplitudeUpdate") {
2768 calMaxAmplitude_ = false;
2769 if (jsPlayer->player_ != nullptr) {
2770 (void)jsPlayer->player_->SetMaxAmplitudeCbStatus(calMaxAmplitude_);
2771 }
2772 }
2773 }
2774
JsClearOnCallback(napi_env env,napi_callback_info info)2775 napi_value AVPlayerNapi::JsClearOnCallback(napi_env env, napi_callback_info info)
2776 {
2777 MediaTrace trace("AVPlayerNapi::off");
2778 napi_value result = nullptr;
2779 napi_get_undefined(env, &result);
2780 MEDIA_LOGD("JsClearOnCallback In");
2781
2782 napi_value args[ARRAY_ARG_COUNTS_TWO] = { nullptr }; // args[0]:type, args[1]:callback
2783 size_t argCount = 2; // args[0]:type, args[1]:callback
2784 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2785 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2786
2787 if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
2788 return result;
2789 }
2790
2791 napi_valuetype valueType0 = napi_undefined;
2792 if (argCount < 1) {
2793 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "Mandatory parameters are left unspecified.");
2794 return result;
2795 }
2796
2797 if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
2798 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "type should be string.");
2799 return result;
2800 }
2801
2802 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
2803 jsPlayer->MaxAmplitudeCallbackOff(jsPlayer, callbackName);
2804 MEDIA_LOGI("0x%{public}06" PRIXPTR " set callbackName: %{public}s", FAKE_POINTER(jsPlayer), callbackName.c_str());
2805
2806 jsPlayer->ClearCallbackReference(callbackName);
2807 MEDIA_LOGI("0x%{public}06" PRIXPTR " JsClearOnCallback success", FAKE_POINTER(jsPlayer));
2808 return result;
2809 }
2810
SaveCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)2811 void AVPlayerNapi::SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
2812 {
2813 std::lock_guard<std::mutex> lock(mutex_);
2814 refMap_[callbackName] = ref;
2815 if (playerCb_ != nullptr) {
2816 playerCb_->SaveCallbackReference(callbackName, ref);
2817 }
2818 }
2819
ClearCallbackReference()2820 void AVPlayerNapi::ClearCallbackReference()
2821 {
2822 std::lock_guard<std::mutex> lock(mutex_);
2823 if (playerCb_ != nullptr) {
2824 playerCb_->ClearCallbackReference();
2825 }
2826 refMap_.clear();
2827 }
2828
ClearCallbackReference(const std::string & callbackName)2829 void AVPlayerNapi::ClearCallbackReference(const std::string &callbackName)
2830 {
2831 std::lock_guard<std::mutex> lock(mutex_);
2832 if (playerCb_ != nullptr) {
2833 playerCb_->ClearCallbackReference(callbackName);
2834 }
2835 refMap_.erase(callbackName);
2836 }
2837
NotifyDuration(int32_t duration)2838 void AVPlayerNapi::NotifyDuration(int32_t duration)
2839 {
2840 duration_ = duration;
2841 }
2842
NotifyPosition(int32_t position)2843 void AVPlayerNapi::NotifyPosition(int32_t position)
2844 {
2845 position_ = position;
2846 }
2847
NotifyState(PlayerStates state)2848 void AVPlayerNapi::NotifyState(PlayerStates state)
2849 {
2850 std::lock_guard<std::mutex> lock(taskMutex_);
2851 if (state_ != state) {
2852 state_ = state;
2853 MEDIA_LOGI("0x%{public}06" PRIXPTR " notify %{public}s", FAKE_POINTER(this), GetCurrentState().c_str());
2854 stopWait_ = true;
2855 stateChangeCond_.notify_all();
2856 }
2857 }
2858
NotifyVideoSize(int32_t width,int32_t height)2859 void AVPlayerNapi::NotifyVideoSize(int32_t width, int32_t height)
2860 {
2861 width_ = width;
2862 height_ = height;
2863 }
2864
NotifyIsLiveStream()2865 void AVPlayerNapi::NotifyIsLiveStream()
2866 {
2867 isLiveStream_ = true;
2868 }
2869
NotifyDrmInfoUpdated(const std::multimap<std::string,std::vector<uint8_t>> & infos)2870 void AVPlayerNapi::NotifyDrmInfoUpdated(const std::multimap<std::string, std::vector<uint8_t>> &infos)
2871 {
2872 MEDIA_LOGD("NotifyDrmInfoUpdated");
2873 std::unique_lock<std::shared_mutex> lock(drmMutex_);
2874 for (auto &newItem : infos) {
2875 auto pos = localDrmInfos_.equal_range(newItem.first);
2876 if (pos.first == pos.second && pos.first == localDrmInfos_.end()) {
2877 localDrmInfos_.insert(newItem);
2878 continue;
2879 }
2880 bool isSame = false;
2881 for (; pos.first != pos.second; ++pos.first) {
2882 if (newItem.second == pos.first->second) {
2883 isSame = true;
2884 break;
2885 }
2886 }
2887 if (!isSame) {
2888 localDrmInfos_.insert(newItem);
2889 }
2890 }
2891 }
2892
ResetUserParameters()2893 void AVPlayerNapi::ResetUserParameters()
2894 {
2895 url_.clear();
2896 fileDescriptor_.fd = 0;
2897 fileDescriptor_.offset = 0;
2898 fileDescriptor_.length = -1;
2899 width_ = 0;
2900 height_ = 0;
2901 position_ = -1;
2902 duration_ = -1;
2903 loop_ = false;
2904 }
2905
StartListenCurrentResource()2906 void AVPlayerNapi::StartListenCurrentResource()
2907 {
2908 std::lock_guard<std::mutex> lock(mutex_);
2909 if (playerCb_ != nullptr) {
2910 playerCb_->Start();
2911 }
2912 }
2913
PauseListenCurrentResource()2914 void AVPlayerNapi::PauseListenCurrentResource()
2915 {
2916 std::lock_guard<std::mutex> lock(mutex_);
2917 if (playerCb_ != nullptr) {
2918 playerCb_->Pause();
2919 }
2920 }
2921
2922 /**
2923 * DO NOT hold taskMutex_ before call this function
2924 * AVPlayerCallback::OnErrorCb() hold AVPlayerCallback::mutex_ and wait taskMutex_, may cause dead lock
2925 */
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)2926 void AVPlayerNapi::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
2927 {
2928 std::lock_guard<std::mutex> lock(mutex_);
2929 if (playerCb_ != nullptr) {
2930 playerCb_->OnErrorCb(errorCode, errorMsg);
2931 }
2932 }
2933
GetJsInstance(napi_env env,napi_callback_info info)2934 AVPlayerNapi* AVPlayerNapi::GetJsInstance(napi_env env, napi_callback_info info)
2935 {
2936 size_t argCount = 0;
2937 napi_value jsThis = nullptr;
2938 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
2939 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
2940
2941 AVPlayerNapi *jsPlayer = nullptr;
2942 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
2943 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
2944
2945 return jsPlayer;
2946 }
2947
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)2948 AVPlayerNapi* AVPlayerNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
2949 size_t &argc, napi_value *argv)
2950 {
2951 napi_value jsThis = nullptr;
2952 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
2953 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
2954
2955 AVPlayerNapi *jsPlayer = nullptr;
2956 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
2957 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
2958
2959 return jsPlayer;
2960 }
2961
IsLiveSource() const2962 bool AVPlayerNapi::IsLiveSource() const
2963 {
2964 return isLiveStream_;
2965 }
2966 } // namespace Media
2967 } // namespace OHOS
2968