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