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 #include "common_napi.h"
21 #ifdef SUPPORT_VIDEO
22 #include "surface_utils.h"
23 #endif
24 #include "string_ex.h"
25 #include "player_xcollie.h"
26 #include "media_dfx.h"
27 #ifdef SUPPORT_JSSTACK
28 #include "xpower_event_js.h"
29 #endif
30 #include "av_common.h"
31
32 using namespace OHOS::AudioStandard;
33
34 namespace {
35 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "AVPlayerNapi"};
36 }
37
38 namespace OHOS {
39 namespace Media {
40 thread_local napi_ref AVPlayerNapi::constructor_ = nullptr;
41 const std::string CLASS_NAME = "AVPlayer";
42
AVPlayerNapi()43 AVPlayerNapi::AVPlayerNapi()
44 {
45 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
46 }
47
~AVPlayerNapi()48 AVPlayerNapi::~AVPlayerNapi()
49 {
50 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
51 }
52
Init(napi_env env,napi_value exports)53 napi_value AVPlayerNapi::Init(napi_env env, napi_value exports)
54 {
55 napi_property_descriptor staticProperty[] = {
56 DECLARE_NAPI_STATIC_FUNCTION("createAVPlayer", JsCreateAVPlayer),
57 };
58
59 napi_property_descriptor properties[] = {
60 DECLARE_NAPI_FUNCTION("prepare", JsPrepare),
61 DECLARE_NAPI_FUNCTION("play", JsPlay),
62 DECLARE_NAPI_FUNCTION("pause", JsPause),
63 DECLARE_NAPI_FUNCTION("stop", JsStop),
64 DECLARE_NAPI_FUNCTION("reset", JsReset),
65 DECLARE_NAPI_FUNCTION("release", JsRelease),
66 DECLARE_NAPI_FUNCTION("seek", JsSeek),
67 DECLARE_NAPI_FUNCTION("on", JsSetOnCallback),
68 DECLARE_NAPI_FUNCTION("off", JsClearOnCallback),
69 DECLARE_NAPI_FUNCTION("setVolume", JsSetVolume),
70 DECLARE_NAPI_FUNCTION("setSpeed", JsSetSpeed),
71 DECLARE_NAPI_FUNCTION("setBitrate", JsSelectBitrate),
72 DECLARE_NAPI_FUNCTION("getTrackDescription", JsGetTrackDescription),
73 DECLARE_NAPI_FUNCTION("selectTrack", JsSelectTrack),
74 DECLARE_NAPI_FUNCTION("deselectTrack", JsDeselectTrack),
75 DECLARE_NAPI_FUNCTION("getCurrentTrack", JsGetCurrentTrack),
76 DECLARE_NAPI_FUNCTION("addSubtitleUrl", JsAddSubtitleUrl),
77 DECLARE_NAPI_FUNCTION("addSubtitleFdSrc", JsAddSubtitleAVFileDescriptor),
78
79 DECLARE_NAPI_GETTER_SETTER("url", JsGetUrl, JsSetUrl),
80 DECLARE_NAPI_GETTER_SETTER("fdSrc", JsGetAVFileDescriptor, JsSetAVFileDescriptor),
81 DECLARE_NAPI_GETTER_SETTER("dataSrc", JsGetDataSrc, JsSetDataSrc),
82 DECLARE_NAPI_GETTER_SETTER("surfaceId", JsGetSurfaceID, JsSetSurfaceID),
83 DECLARE_NAPI_GETTER_SETTER("loop", JsGetLoop, JsSetLoop),
84 DECLARE_NAPI_GETTER_SETTER("videoScaleType", JsGetVideoScaleType, JsSetVideoScaleType),
85 DECLARE_NAPI_GETTER_SETTER("audioInterruptMode", JsGetAudioInterruptMode, JsSetAudioInterruptMode),
86 DECLARE_NAPI_GETTER_SETTER("audioRendererInfo", JsGetAudioRendererInfo, JsSetAudioRendererInfo),
87 DECLARE_NAPI_GETTER_SETTER("audioEffectMode", JsGetAudioEffectMode, JsSetAudioEffectMode),
88
89 DECLARE_NAPI_GETTER("state", JsGetState),
90 DECLARE_NAPI_GETTER("currentTime", JsGetCurrentTime),
91 DECLARE_NAPI_GETTER("duration", JsGetDuration),
92 DECLARE_NAPI_GETTER("width", JsGetWidth),
93 DECLARE_NAPI_GETTER("height", JsGetHeight),
94 };
95
96 napi_value constructor = nullptr;
97 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
98 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
99 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVPlayer class");
100
101 status = napi_create_reference(env, constructor, 1, &constructor_);
102 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
103
104 status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
105 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
106
107 status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
108 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
109
110 MEDIA_LOGI("Init success");
111 return exports;
112 }
113
Constructor(napi_env env,napi_callback_info info)114 napi_value AVPlayerNapi::Constructor(napi_env env, napi_callback_info info)
115 {
116 napi_value result = nullptr;
117 napi_get_undefined(env, &result);
118
119 size_t argCount = 0;
120 napi_value jsThis = nullptr;
121 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
122 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
123
124 AVPlayerNapi *jsPlayer = new(std::nothrow) AVPlayerNapi();
125 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to new AVPlayerNapi");
126
127 jsPlayer->env_ = env;
128 jsPlayer->player_ = PlayerFactory::CreatePlayer();
129 CHECK_AND_RETURN_RET_LOG(jsPlayer->player_ != nullptr, result, "failed to CreatePlayer");
130
131 jsPlayer->taskQue_ = std::make_unique<TaskQueue>("AVPlayerNapi");
132 (void)jsPlayer->taskQue_->Start();
133
134 jsPlayer->playerCb_ = std::make_shared<AVPlayerCallback>(env, jsPlayer);
135 (void)jsPlayer->player_->SetPlayerCallback(jsPlayer->playerCb_);
136
137 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsPlayer),
138 AVPlayerNapi::Destructor, nullptr, nullptr);
139 if (status != napi_ok) {
140 delete jsPlayer;
141 MEDIA_LOGE("Failed to wrap native instance");
142 return result;
143 }
144
145 MEDIA_LOGI("Constructor success");
146 return jsThis;
147 }
148
Destructor(napi_env env,void * nativeObject,void * finalize)149 void AVPlayerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
150 {
151 (void)env;
152 (void)finalize;
153 if (nativeObject != nullptr) {
154 AVPlayerNapi *jsPlayer = reinterpret_cast<AVPlayerNapi *>(nativeObject);
155 jsPlayer->ClearCallbackReference();
156 auto task = jsPlayer->ReleaseTask();
157 if (task != nullptr) {
158 MEDIA_LOGI("Destructor Wait Release Task Start");
159 task->GetResult(); // sync release
160 MEDIA_LOGI("Destructor Wait Release Task End");
161 }
162 jsPlayer->WaitTaskQueStop();
163 delete jsPlayer;
164 }
165 MEDIA_LOGI("Destructor success");
166 }
167
JsCreateAVPlayer(napi_env env,napi_callback_info info)168 napi_value AVPlayerNapi::JsCreateAVPlayer(napi_env env, napi_callback_info info)
169 {
170 MediaTrace trace("AVPlayerNapi::createAVPlayer");
171 napi_value result = nullptr;
172 napi_get_undefined(env, &result);
173 MEDIA_LOGI("JsCreateAVPlayer In");
174
175 std::unique_ptr<MediaAsyncContext> asyncContext = std::make_unique<MediaAsyncContext>(env);
176
177 // get args
178 napi_value jsThis = nullptr;
179 napi_value args[1] = { nullptr };
180 size_t argCount = 1;
181 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
182 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
183
184 asyncContext->callbackRef = CommonNapi::CreateReference(env, args[0]);
185 asyncContext->deferred = CommonNapi::CreatePromise(env, asyncContext->callbackRef, result);
186 asyncContext->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
187 asyncContext->ctorFlag = true;
188
189 napi_value resource = nullptr;
190 napi_create_string_utf8(env, "JsCreateAVPlayer", NAPI_AUTO_LENGTH, &resource);
191 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {},
192 MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncContext.get()), &asyncContext->work));
193 napi_queue_async_work_with_qos(env, asyncContext->work, napi_qos_user_initiated);
194 asyncContext.release();
195 MEDIA_LOGI("JsCreateAVPlayer Out");
196 return result;
197 }
198
PrepareTask()199 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PrepareTask()
200 {
201 auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
202 MEDIA_LOGI("Prepare Task In");
203 std::unique_lock<std::mutex> lock(taskMutex_);
204 auto state = GetCurrentState();
205 if (state == AVPlayerState::STATE_INITIALIZED ||
206 state == AVPlayerState::STATE_STOPPED) {
207 int32_t ret = player_->PrepareAsync();
208 if (ret != MSERR_OK) {
209 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
210 return TaskRet(errCode, "failed to prepare");
211 }
212 stopWait_ = false;
213 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "PrepareTask", false)
214
215 if (GetCurrentState() == AVPlayerState::STATE_ERROR) {
216 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
217 "failed to prepare, avplayer enter error status, please check error callback messages!");
218 }
219 } else if (state == AVPlayerState::STATE_PREPARED) {
220 MEDIA_LOGI("current state is prepared, invalid operation");
221 } else {
222 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
223 "current state is not stopped or initialized, unsupport prepare operation");
224 }
225
226 MEDIA_LOGI("Prepare Task Out");
227 return TaskRet(MSERR_EXT_API9_OK, "Success");
228 });
229
230 (void)taskQue_->EnqueueTask(task);
231 return task;
232 }
233
JsPrepare(napi_env env,napi_callback_info info)234 napi_value AVPlayerNapi::JsPrepare(napi_env env, napi_callback_info info)
235 {
236 MediaTrace trace("AVPlayerNapi::prepare");
237 napi_value result = nullptr;
238 napi_get_undefined(env, &result);
239 MEDIA_LOGI("JsPrepare In");
240
241 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
242 napi_value args[1] = { nullptr };
243 size_t argCount = 1;
244 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
245 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
246
247 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
248 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
249 auto state = jsPlayer->GetCurrentState();
250 if (state != AVPlayerState::STATE_INITIALIZED &&
251 state != AVPlayerState::STATE_STOPPED &&
252 state != AVPlayerState::STATE_PREPARED) {
253 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
254 "current state is not stopped or initialized, unsupport prepare operation");
255 } else {
256 promiseCtx->asyncTask = jsPlayer->PrepareTask();
257 }
258
259 napi_value resource = nullptr;
260 napi_create_string_utf8(env, "JsPrepare", NAPI_AUTO_LENGTH, &resource);
261 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
262 [](napi_env env, void *data) {
263 MEDIA_LOGI("Wait Prepare Task Start");
264 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
265 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
266 promiseCtx->CheckTaskResult();
267 MEDIA_LOGI("Wait Prepare Task End");
268 },
269 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
270 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
271 promiseCtx.release();
272 MEDIA_LOGI("JsPrepare Out");
273 return result;
274 }
275
PlayTask()276 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PlayTask()
277 {
278 auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
279 MEDIA_LOGI("Play Task In");
280 std::unique_lock<std::mutex> lock(taskMutex_);
281 auto state = GetCurrentState();
282 if (state == AVPlayerState::STATE_PREPARED ||
283 state == AVPlayerState::STATE_PAUSED ||
284 state == AVPlayerState::STATE_COMPLETED) {
285 int32_t ret = player_->Play();
286 if (ret != MSERR_OK) {
287 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
288 return TaskRet(errCode, "failed to Play");
289 }
290 stopWait_ = false;
291 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "PlayTask", false)
292 } else if (state == AVPlayerState::STATE_PLAYING) {
293 MEDIA_LOGI("current state is playing, invalid operation");
294 } else {
295 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
296 "current state is not prepared/paused/completed, unsupport play operation");
297 }
298
299 MEDIA_LOGI("Play Task Out");
300 return TaskRet(MSERR_EXT_API9_OK, "Success");
301 });
302 (void)taskQue_->EnqueueTask(task);
303 return task;
304 }
305
JsPlay(napi_env env,napi_callback_info info)306 napi_value AVPlayerNapi::JsPlay(napi_env env, napi_callback_info info)
307 {
308 MediaTrace trace("AVPlayerNapi::play");
309 napi_value result = nullptr;
310 napi_get_undefined(env, &result);
311 MEDIA_LOGI("JsPlay In");
312
313 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
314 napi_value args[1] = { nullptr };
315 size_t argCount = 1;
316 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
317 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
318
319 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
320 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
321 auto state = jsPlayer->GetCurrentState();
322 if (state != AVPlayerState::STATE_PREPARED &&
323 state != AVPlayerState::STATE_PAUSED &&
324 state != AVPlayerState::STATE_COMPLETED &&
325 state != AVPlayerState::STATE_PLAYING) {
326 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
327 "current state is not prepared/paused/completed, unsupport play operation");
328 } else if (state == AVPlayerState::STATE_COMPLETED && jsPlayer->IsLiveSource()) {
329 promiseCtx->SignError(MSERR_EXT_API9_UNSUPPORT_CAPABILITY,
330 "In live mode, replay not be allowed.");
331 } else {
332 promiseCtx->asyncTask = jsPlayer->PlayTask();
333 }
334 #ifdef SUPPORT_JSSTACK
335 HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
336 #endif
337 napi_value resource = nullptr;
338 napi_create_string_utf8(env, "JsPlay", NAPI_AUTO_LENGTH, &resource);
339 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
340 [](napi_env env, void *data) {
341 MEDIA_LOGI("Wait JsPlay Task Start");
342 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
343 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
344 promiseCtx->CheckTaskResult();
345 MEDIA_LOGI("Wait JsPlay Task End");
346 },
347 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
348 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
349 promiseCtx.release();
350 MEDIA_LOGI("JsPlay Out");
351 return result;
352 }
353
PauseTask()354 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::PauseTask()
355 {
356 auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
357 MEDIA_LOGI("Pause Task In");
358 std::unique_lock<std::mutex> lock(taskMutex_);
359 auto state = GetCurrentState();
360 if (state == AVPlayerState::STATE_PLAYING) {
361 int32_t ret = player_->Pause();
362 if (ret != MSERR_OK) {
363 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
364 return TaskRet(errCode, "failed to Pause");
365 }
366 stopWait_ = false;
367 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "PauseTask", false)
368 } else if (state == AVPlayerState::STATE_PAUSED) {
369 MEDIA_LOGI("current state is paused, invalid operation");
370 } else {
371 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
372 "current state is not playing, unsupport pause operation");
373 }
374
375 MEDIA_LOGI("Pause Task Out");
376 return TaskRet(MSERR_EXT_API9_OK, "Success");
377 });
378 (void)taskQue_->EnqueueTask(task);
379 return task;
380 }
381
JsPause(napi_env env,napi_callback_info info)382 napi_value AVPlayerNapi::JsPause(napi_env env, napi_callback_info info)
383 {
384 MediaTrace trace("AVPlayerNapi::pause");
385 napi_value result = nullptr;
386 napi_get_undefined(env, &result);
387 MEDIA_LOGI("JsPause In");
388
389 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
390 napi_value args[1] = { nullptr };
391 size_t argCount = 1;
392 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
393 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
394
395 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
396 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
397 auto state = jsPlayer->GetCurrentState();
398 if (state != AVPlayerState::STATE_PLAYING &&
399 state != AVPlayerState::STATE_PAUSED) {
400 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
401 "current state is not playing, unsupport pause operation");
402 } else {
403 promiseCtx->asyncTask = jsPlayer->PauseTask();
404 }
405
406 napi_value resource = nullptr;
407 napi_create_string_utf8(env, "JsPause", NAPI_AUTO_LENGTH, &resource);
408 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
409 [](napi_env env, void *data) {
410 MEDIA_LOGI("Wait JsPause Task Start");
411 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
412 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
413 promiseCtx->CheckTaskResult();
414 MEDIA_LOGI("Wait JsPause Task End");
415 },
416 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
417 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
418 promiseCtx.release();
419 MEDIA_LOGI("JsPause Out");
420 return result;
421 }
422
StopTask()423 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::StopTask()
424 {
425 auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
426 MEDIA_LOGI("Stop Task In");
427 std::unique_lock<std::mutex> lock(taskMutex_);
428 if (IsControllable()) {
429 int32_t ret = player_->Stop();
430 if (ret != MSERR_OK) {
431 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
432 return TaskRet(errCode, "failed to Stop");
433 }
434 stopWait_ = false;
435 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "StopTask", false)
436 } else if (GetCurrentState() == AVPlayerState::STATE_STOPPED) {
437 MEDIA_LOGI("current state is stopped, invalid operation");
438 } else {
439 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
440 "current state is not prepared/playing/paused/completed, unsupport stop operation");
441 }
442
443 MEDIA_LOGI("Stop Task Out");
444 return TaskRet(MSERR_EXT_API9_OK, "Success");
445 });
446 (void)taskQue_->EnqueueTask(task);
447 return task;
448 }
449
JsStop(napi_env env,napi_callback_info info)450 napi_value AVPlayerNapi::JsStop(napi_env env, napi_callback_info info)
451 {
452 MediaTrace trace("AVPlayerNapi::stop");
453 napi_value result = nullptr;
454 napi_get_undefined(env, &result);
455 MEDIA_LOGI("JsStop In");
456
457 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
458 napi_value args[1] = { nullptr };
459 size_t argCount = 1;
460 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
461 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
462
463 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
464 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
465 auto state = jsPlayer->GetCurrentState();
466 if (state == AVPlayerState::STATE_IDLE ||
467 state == AVPlayerState::STATE_INITIALIZED ||
468 state == AVPlayerState::STATE_RELEASED ||
469 state == AVPlayerState::STATE_ERROR) {
470 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
471 "current state is not prepared/playing/paused/completed, unsupport stop operation");
472 } else {
473 promiseCtx->asyncTask = jsPlayer->StopTask();
474 }
475
476 napi_value resource = nullptr;
477 napi_create_string_utf8(env, "JsStop", NAPI_AUTO_LENGTH, &resource);
478 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
479 [](napi_env env, void *data) {
480 MEDIA_LOGI("Wait JsStop Task Start");
481 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
482 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
483 promiseCtx->CheckTaskResult();
484 MEDIA_LOGI("Wait JsStop Task End");
485 },
486 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
487 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
488 promiseCtx.release();
489 MEDIA_LOGI("JsStop Out");
490 return result;
491 }
492
ResetTask()493 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ResetTask()
494 {
495 auto task = std::make_shared<TaskHandler<TaskRet>>([this]() {
496 MEDIA_LOGI("Reset Task In");
497 PauseListenCurrentResource(); // Pause event listening for the current resource
498 ResetUserParameters();
499 {
500 std::unique_lock<std::mutex> lock(taskMutex_);
501 if (GetCurrentState() == AVPlayerState::STATE_RELEASED) {
502 return TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
503 "current state is not playing, unsupport pause operation");
504 } else if (GetCurrentState() == AVPlayerState::STATE_IDLE) {
505 MEDIA_LOGI("current state is idle, invalid operation");
506 } else {
507 int32_t ret = player_->Reset();
508 if (ret != MSERR_OK) {
509 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
510 return TaskRet(errCode, "failed to Reset");
511 }
512 stopWait_ = false;
513 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "ResetTask", false)
514 }
515 }
516 MEDIA_LOGI("Reset Task Out");
517 return TaskRet(MSERR_EXT_API9_OK, "Success");
518 });
519
520 {
521 std::unique_lock<std::mutex> lock(taskMutex_);
522 (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
523 stopWait_ = true;
524 stateChangeCond_.notify_all();
525 }
526 return task;
527 }
528
JsReset(napi_env env,napi_callback_info info)529 napi_value AVPlayerNapi::JsReset(napi_env env, napi_callback_info info)
530 {
531 MediaTrace trace("AVPlayerNapi::reset");
532 napi_value result = nullptr;
533 napi_get_undefined(env, &result);
534 MEDIA_LOGI("JsReset In");
535
536 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
537 napi_value args[1] = { nullptr };
538 size_t argCount = 1;
539 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
540 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
541 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
542 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
543 if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
544 promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
545 "current state is released, unsupport reset operation");
546 } else {
547 promiseCtx->asyncTask = jsPlayer->ResetTask();
548 if (jsPlayer->dataSrcCb_ != nullptr) {
549 jsPlayer->dataSrcCb_->ClearCallbackReference();
550 jsPlayer->dataSrcCb_ = nullptr;
551 }
552 jsPlayer->isLiveStream_ = false;
553 }
554
555 napi_value resource = nullptr;
556 napi_create_string_utf8(env, "JsReset", NAPI_AUTO_LENGTH, &resource);
557 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
558 [](napi_env env, void *data) {
559 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
560 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
561 if (promiseCtx->asyncTask != nullptr) {
562 MEDIA_LOGI("Wait Reset Task Start");
563 promiseCtx->CheckTaskResult();
564 MEDIA_LOGI("Wait Reset Task Stop");
565 }
566 },
567 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
568 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
569 promiseCtx.release();
570 MEDIA_LOGI("JsReset Out");
571 return result;
572 }
573
WaitTaskQueStop()574 void AVPlayerNapi::WaitTaskQueStop()
575 {
576 MEDIA_LOGI("WaitTaskQueStop In");
577 std::unique_lock<std::mutex> lock(taskMutex_);
578 LISTENER(stopTaskQueCond_.wait(lock, [this]() { return taskQueStoped_; }), "StopTaskQue", false)
579 MEDIA_LOGI("WaitTaskQueStop Out");
580 }
581
StopTaskQue()582 void AVPlayerNapi::StopTaskQue()
583 {
584 MEDIA_LOGI("StopTaskQue In");
585 taskQue_->Stop();
586 taskQueStoped_ = true;
587 stopTaskQueCond_.notify_all();
588 MEDIA_LOGI("StopTaskQue Out");
589 }
590
ReleaseTask()591 std::shared_ptr<TaskHandler<TaskRet>> AVPlayerNapi::ReleaseTask()
592 {
593 std::shared_ptr<TaskHandler<TaskRet>> task = nullptr;
594 if (!isReleased_.load()) {
595 task = std::make_shared<TaskHandler<TaskRet>>([this]() {
596 MEDIA_LOGI("Release Task In");
597 PauseListenCurrentResource(); // Pause event listening for the current resource
598 ResetUserParameters();
599
600 if (player_ != nullptr) {
601 (void)player_->ReleaseSync();
602 player_ = nullptr;
603 }
604
605 if (playerCb_ != nullptr) {
606 playerCb_->Release();
607 }
608 MEDIA_LOGI("Release Task Out");
609 std::thread(&AVPlayerNapi::StopTaskQue, this).detach();
610 return TaskRet(MSERR_EXT_API9_OK, "Success");
611 });
612
613 std::unique_lock<std::mutex> lock(taskMutex_);
614 isReleased_.store(true);
615 (void)taskQue_->EnqueueTask(task, true); // CancelNotExecutedTask
616 stopWait_ = true;
617 stateChangeCond_.notify_all();
618 }
619 return task;
620 }
621
JsRelease(napi_env env,napi_callback_info info)622 napi_value AVPlayerNapi::JsRelease(napi_env env, napi_callback_info info)
623 {
624 MediaTrace trace("AVPlayerNapi::release");
625 napi_value result = nullptr;
626 napi_get_undefined(env, &result);
627 MEDIA_LOGI("JsRelease In");
628
629 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
630 napi_value args[1] = { nullptr };
631 size_t argCount = 1;
632 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
633 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
634 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
635 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
636 promiseCtx->asyncTask = jsPlayer->ReleaseTask();
637 if (jsPlayer->dataSrcCb_ != nullptr) {
638 jsPlayer->dataSrcCb_->ClearCallbackReference();
639 jsPlayer->dataSrcCb_ = nullptr;
640 }
641
642 napi_value resource = nullptr;
643 napi_create_string_utf8(env, "JsRelease", NAPI_AUTO_LENGTH, &resource);
644 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
645 [](napi_env env, void *data) {
646 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
647 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
648 if (promiseCtx->asyncTask != nullptr) {
649 MEDIA_LOGI("Wait Release Task Start");
650 promiseCtx->CheckTaskResult();
651 MEDIA_LOGI("Wait Release Task Stop");
652 }
653 },
654 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
655 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
656 promiseCtx.release();
657 MEDIA_LOGI("JsRelease Out");
658 return result;
659 }
660
JsSeek(napi_env env,napi_callback_info info)661 napi_value AVPlayerNapi::JsSeek(napi_env env, napi_callback_info info)
662 {
663 MediaTrace trace("AVPlayerNapi::seek");
664 napi_value result = nullptr;
665 napi_get_undefined(env, &result);
666 MEDIA_LOGI("JsSeek In");
667
668 napi_value args[2] = { nullptr }; // args[0]:timeMs, args[1]:SeekMode
669 size_t argCount = 2; // args[0]:timeMs, args[1]:SeekMode
670 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
671 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
672
673 if (jsPlayer->IsLiveSource()) {
674 jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support seek");
675 return result;
676 }
677
678 napi_valuetype valueType = napi_undefined;
679 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
680 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek time is not number");
681 return result;
682 }
683
684 int32_t time = -1;
685 napi_status status = napi_get_value_int32(env, args[0], &time);
686 if (status != napi_ok || time < 0) {
687 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input seek time");
688 return result;
689 }
690
691 int32_t mode = SEEK_PREVIOUS_SYNC;
692 if (args[1] != nullptr) {
693 if (napi_typeof(env, args[1], &valueType) != napi_ok || valueType != napi_number) {
694 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "seek mode is not number");
695 return result;
696 }
697 status = napi_get_value_int32(env, args[1], &mode);
698 if (status != napi_ok || mode < SEEK_NEXT_SYNC || mode > SEEK_CLOSEST) {
699 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check seek mode");
700 return result;
701 }
702 }
703
704 if (!jsPlayer->IsControllable()) {
705 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
706 "current state is not prepared/playing/paused/completed, unsupport seek operation");
707 return result;
708 }
709
710 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, time, mode]() {
711 MEDIA_LOGI("Seek Task");
712 if (jsPlayer->player_ != nullptr) {
713 (void)jsPlayer->player_->Seek(time, static_cast<PlayerSeekMode>(mode));
714 }
715 });
716 (void)jsPlayer->taskQue_->EnqueueTask(task);
717 return result;
718 }
719
JsSetSpeed(napi_env env,napi_callback_info info)720 napi_value AVPlayerNapi::JsSetSpeed(napi_env env, napi_callback_info info)
721 {
722 MediaTrace trace("AVPlayerNapi::setSpeed");
723 napi_value result = nullptr;
724 napi_get_undefined(env, &result);
725 MEDIA_LOGI("JsSetSpeed In");
726
727 napi_value args[1] = { nullptr };
728 size_t argCount = 1; // setSpeed(speed: number)
729 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
730 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
731
732 if (jsPlayer->IsLiveSource()) {
733 jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support speed");
734 return result;
735 }
736
737 napi_valuetype valueType = napi_undefined;
738 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
739 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "speed mode is not number");
740 return result;
741 }
742
743 int32_t mode = SPEED_FORWARD_1_00_X;
744 napi_status status = napi_get_value_int32(env, args[0], &mode);
745 if (status != napi_ok || mode < SPEED_FORWARD_0_75_X || mode > SPEED_FORWARD_2_00_X) {
746 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
747 "invalid parameters, please check the speed mode");
748 return result;
749 }
750
751 if (!jsPlayer->IsControllable()) {
752 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
753 "current state is not prepared/playing/paused/completed, unsupport speed operation");
754 return result;
755 }
756
757 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, mode]() {
758 MEDIA_LOGI("Speed Task");
759 if (jsPlayer->player_ != nullptr) {
760 (void)jsPlayer->player_->SetPlaybackSpeed(static_cast<PlaybackRateMode>(mode));
761 }
762 });
763 (void)jsPlayer->taskQue_->EnqueueTask(task);
764 MEDIA_LOGI("JsSetSpeed Out");
765 return result;
766 }
767
JsSetVolume(napi_env env,napi_callback_info info)768 napi_value AVPlayerNapi::JsSetVolume(napi_env env, napi_callback_info info)
769 {
770 MediaTrace trace("AVPlayerNapi::setVolume");
771 napi_value result = nullptr;
772 napi_get_undefined(env, &result);
773 MEDIA_LOGI("JsSetVolume In");
774
775 napi_value args[1] = { nullptr };
776 size_t argCount = 1; // setVolume(vol: number)
777 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
778 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
779
780 napi_valuetype valueType = napi_undefined;
781 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
782 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "setVolume level is not number");
783 return result;
784 }
785
786 double volumeLevel = 1.0f;
787 napi_status status = napi_get_value_double(env, args[0], &volumeLevel);
788 if (status != napi_ok || volumeLevel < 0.0f || volumeLevel > 1.0f) {
789 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, check volume level");
790 return result;
791 }
792
793 if (!jsPlayer->IsControllable()) {
794 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
795 "current state is not prepared/playing/paused/completed, unsupport volume operation");
796 return result;
797 }
798 #ifdef SUPPORT_JSSTACK
799 HiviewDFX::ReportXPowerJsStackSysEvent(env, "VOLUME_CHANGE", "SRC=Media");
800 #endif
801 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, volumeLevel]() {
802 MEDIA_LOGI("SetVolume Task");
803 if (jsPlayer->player_ != nullptr) {
804 (void)jsPlayer->player_->SetVolume(volumeLevel, volumeLevel);
805 }
806 });
807 (void)jsPlayer->taskQue_->EnqueueTask(task);
808 MEDIA_LOGI("JsSetVolume Out");
809 return result;
810 }
811
JsSelectBitrate(napi_env env,napi_callback_info info)812 napi_value AVPlayerNapi::JsSelectBitrate(napi_env env, napi_callback_info info)
813 {
814 MediaTrace trace("AVPlayerNapi::setBitrate");
815 napi_value result = nullptr;
816 napi_get_undefined(env, &result);
817 MEDIA_LOGI("JsSelectBitrate In");
818
819 napi_value args[1] = { nullptr };
820 size_t argCount = 1; // selectBitrate(bitRate: number)
821 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
822 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
823
824 napi_valuetype valueType = napi_undefined;
825 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
826 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "selectBitrate is not number");
827 return result;
828 }
829
830 int32_t bitrate = 0;
831 napi_status status = napi_get_value_int32(env, args[0], &bitrate);
832 if (status != napi_ok || bitrate < 0) {
833 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input bitrate");
834 return result;
835 }
836
837 if (!jsPlayer->IsControllable()) {
838 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
839 "current state is not prepared/playing/paused/completed, unsupport select bitrate operation");
840 return result;
841 }
842
843 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, bitrate]() {
844 MEDIA_LOGI("SelectBitRate Task");
845 if (jsPlayer->player_ != nullptr) {
846 (void)jsPlayer->player_->SelectBitRate(static_cast<uint32_t>(bitrate));
847 }
848 });
849 (void)jsPlayer->taskQue_->EnqueueTask(task);
850 return result;
851 }
852
AddSubSource(std::string url)853 void AVPlayerNapi::AddSubSource(std::string url)
854 {
855 MEDIA_LOGI("input url is %{public}s!", url.c_str());
856 bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
857 bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
858 if (isNetwork) {
859 auto task = std::make_shared<TaskHandler<void>>([this, url]() {
860 MEDIA_LOGI("AddSubtitleNetworkSource Task");
861 if (player_ != nullptr) {
862 if (player_->AddSubSource(url) != MSERR_OK) {
863 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to AddSubtitleNetworkSource");
864 }
865 }
866 });
867 (void)taskQue_->EnqueueTask(task);
868 } else if (isFd) {
869 const std::string fdHead = "fd://";
870 std::string inputFd = url.substr(fdHead.size());
871 int32_t fd = -1;
872 if (!StrToInt(inputFd, fd) || fd < 0) {
873 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
874 "invalid parameters, The input parameter is not a fd://+numeric string");
875 return;
876 }
877
878 auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
879 MEDIA_LOGI("AddSubtitleFdSource Task");
880 if (player_ != nullptr) {
881 if (player_->AddSubSource(fd, 0, -1) != MSERR_OK) {
882 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to AddSubtitleFdSource");
883 }
884 }
885 });
886 (void)taskQue_->EnqueueTask(task);
887 } else {
888 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
889 "invalid parameters, The input parameter is not fd:// or network address");
890 }
891 }
892
JsAddSubtitleUrl(napi_env env,napi_callback_info info)893 napi_value AVPlayerNapi::JsAddSubtitleUrl(napi_env env, napi_callback_info info)
894 {
895 MediaTrace trace("AVPlayerNapi::addSubtitleUrl");
896 napi_value result = nullptr;
897 napi_get_undefined(env, &result);
898 MEDIA_LOGI("JsAddSubtitleUrl In");
899
900 napi_value args[1] = { nullptr };
901 size_t argCount = 1; // addSubtitleUrl(url: string)
902 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
903 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
904
905 if (!jsPlayer->IsControllable()) {
906 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
907 "current state is not prepared/playing/paused/completed, unsupport add subtitle source operation");
908 return result;
909 }
910
911 napi_valuetype valueType = napi_undefined;
912 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
913 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
914 return result;
915 }
916
917 // get subUrl from js
918 std::string subUrl = CommonNapi::GetStringArgument(env, args[0]);
919 jsPlayer->AddSubSource(subUrl);
920
921 MEDIA_LOGI("JsAddSubtitleUrl Out");
922 return result;
923 }
924
JsAddSubtitleAVFileDescriptor(napi_env env,napi_callback_info info)925 napi_value AVPlayerNapi::JsAddSubtitleAVFileDescriptor(napi_env env, napi_callback_info info)
926 {
927 napi_value result = nullptr;
928 napi_get_undefined(env, &result);
929 MEDIA_LOGI("JsAddSubtitleAVFileDescriptor In");
930
931 napi_value args[1] = { nullptr };
932 size_t argCount = 1; // url: string
933 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
934 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
935
936 if (!jsPlayer->IsControllable()) {
937 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
938 "current state is not prepared/playing/paused/completed, unsupport add subtitle fd operation");
939 return result;
940 }
941
942 napi_valuetype valueType = napi_undefined;
943 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
944 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "fileDescriptor is not napi_object");
945 return result;
946 }
947
948 struct AVFileDescriptor playerFd;
949 if (!CommonNapi::GetFdArgument(env, args[0], playerFd)) {
950 MEDIA_LOGE("get fileDescriptor argument failed!");
951 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
952 "invalid parameters, please check the input parameters(fileDescriptor)");
953 return result;
954 }
955
956 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, playerFd]() {
957 MEDIA_LOGI("AddSubtitleAVFileDescriptor Task");
958 if (jsPlayer->player_ != nullptr) {
959 if (jsPlayer->player_->AddSubSource(playerFd.fd, playerFd.offset, playerFd.length) != MSERR_OK) {
960 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to AddSubtitleAVFileDescriptor");
961 }
962 }
963 });
964 (void)jsPlayer->taskQue_->EnqueueTask(task);
965
966 MEDIA_LOGI("JsAddSubtitleAVFileDescriptor Out");
967 return result;
968 }
969
SetSource(std::string url)970 void AVPlayerNapi::SetSource(std::string url)
971 {
972 MEDIA_LOGI("input url is %{public}s!", url.c_str());
973 bool isFd = (url.find("fd://") != std::string::npos) ? true : false;
974 bool isNetwork = (url.find("http") != std::string::npos) ? true : false;
975 if (isNetwork) {
976 auto task = std::make_shared<TaskHandler<void>>([this, url]() {
977 MEDIA_LOGI("SetNetworkSource Task");
978 std::unique_lock<std::mutex> lock(taskMutex_);
979 auto state = GetCurrentState();
980 if (state != AVPlayerState::STATE_IDLE) {
981 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
982 return;
983 }
984 if (player_ != nullptr) {
985 if (player_->SetSource(url) != MSERR_OK) {
986 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "failed to SetSourceNetWork");
987 }
988 stopWait_ = false;
989 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "SetSourceNetWork", false)
990 }
991 });
992 (void)taskQue_->EnqueueTask(task);
993 } else if (isFd) {
994 std::string inputFd = url.substr(sizeof("fd://") - 1);
995 int32_t fd = -1;
996 if (!StrToInt(inputFd, fd) || fd < 0) {
997 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
998 "invalid parameters, The input parameter is not a fd://+numeric string");
999 return;
1000 }
1001
1002 auto task = std::make_shared<TaskHandler<void>>([this, fd]() {
1003 MEDIA_LOGI("SetFdSource Task");
1004 std::unique_lock<std::mutex> lock(taskMutex_);
1005 auto state = GetCurrentState();
1006 if (state != AVPlayerState::STATE_IDLE) {
1007 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set source fd");
1008 return;
1009 }
1010 if (player_ != nullptr) {
1011 if (player_->SetSource(fd, 0, -1) != MSERR_OK) {
1012 OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "failed to SetSourceFd");
1013 }
1014 stopWait_ = false;
1015 LISTENER(stateChangeCond_.wait(lock, [this]() { return stopWait_.load(); }), "SetSourceFd", false)
1016 }
1017 });
1018 (void)taskQue_->EnqueueTask(task);
1019 } else {
1020 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1021 "invalid parameters, The input parameter is not fd:// or network address");
1022 }
1023 }
1024
JsSetUrl(napi_env env,napi_callback_info info)1025 napi_value AVPlayerNapi::JsSetUrl(napi_env env, napi_callback_info info)
1026 {
1027 MediaTrace trace("AVPlayerNapi::set url");
1028 napi_value result = nullptr;
1029 napi_get_undefined(env, &result);
1030 MEDIA_LOGI("JsSetUrl In");
1031
1032 napi_value args[1] = { nullptr };
1033 size_t argCount = 1; // url: string
1034 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1035 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1036
1037 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
1038 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set url");
1039 return result;
1040 }
1041
1042 jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
1043 napi_valuetype valueType = napi_undefined;
1044 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1045 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "url is not string");
1046 return result;
1047 }
1048
1049 // get url from js
1050 jsPlayer->url_ = CommonNapi::GetStringArgument(env, args[0]);
1051 jsPlayer->SetSource(jsPlayer->url_);
1052
1053 MEDIA_LOGI("JsSetUrl Out");
1054 return result;
1055 }
1056
JsGetUrl(napi_env env,napi_callback_info info)1057 napi_value AVPlayerNapi::JsGetUrl(napi_env env, napi_callback_info info)
1058 {
1059 MediaTrace trace("AVPlayerNapi::get url");
1060 napi_value result = nullptr;
1061 napi_get_undefined(env, &result);
1062 MEDIA_LOGI("JsGetUrl In");
1063
1064 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1065 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1066
1067 napi_value value = nullptr;
1068 (void)napi_create_string_utf8(env, jsPlayer->url_.c_str(), NAPI_AUTO_LENGTH, &value);
1069
1070 MEDIA_LOGI("JsGetUrl Out Current Url: %{public}s", jsPlayer->url_.c_str());
1071 return value;
1072 }
1073
JsSetAVFileDescriptor(napi_env env,napi_callback_info info)1074 napi_value AVPlayerNapi::JsSetAVFileDescriptor(napi_env env, napi_callback_info info)
1075 {
1076 MediaTrace trace("AVPlayerNapi::set fd");
1077 napi_value result = nullptr;
1078 napi_get_undefined(env, &result);
1079 MEDIA_LOGI("JsSetAVFileDescriptor In");
1080
1081 napi_value args[1] = { nullptr };
1082 size_t argCount = 1; // url: string
1083 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1084 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1085
1086 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
1087 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set fd");
1088 return result;
1089 }
1090
1091 jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
1092 napi_valuetype valueType = napi_undefined;
1093 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
1094 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAVFileDescriptor is not napi_object");
1095 return result;
1096 }
1097
1098 if (!CommonNapi::GetFdArgument(env, args[0], jsPlayer->fileDescriptor_)) {
1099 MEDIA_LOGE("get fileDescriptor argument failed!");
1100 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1101 "invalid parameters, please check the input parameters(fileDescriptor)");
1102 return result;
1103 }
1104
1105 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1106 MEDIA_LOGI("SetAVFileDescriptor Task");
1107 if (jsPlayer->player_ != nullptr) {
1108 auto playerFd = jsPlayer->fileDescriptor_;
1109 if (jsPlayer->player_->SetSource(playerFd.fd, playerFd.offset, playerFd.length) != MSERR_OK) {
1110 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource FileDescriptor failed");
1111 }
1112 }
1113 });
1114 (void)jsPlayer->taskQue_->EnqueueTask(task);
1115
1116 MEDIA_LOGI("JsSetAVFileDescriptor Out");
1117 return result;
1118 }
1119
JsGetAVFileDescriptor(napi_env env,napi_callback_info info)1120 napi_value AVPlayerNapi::JsGetAVFileDescriptor(napi_env env, napi_callback_info info)
1121 {
1122 MediaTrace trace("AVPlayerNapi::get fd");
1123 napi_value result = nullptr;
1124 napi_get_undefined(env, &result);
1125 MEDIA_LOGI("JsGetAVFileDescriptor In");
1126
1127 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1128 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1129
1130 napi_value value = nullptr;
1131 (void)napi_create_object(env, &value);
1132 (void)CommonNapi::AddNumberPropInt32(env, value, "fd", jsPlayer->fileDescriptor_.fd);
1133 (void)CommonNapi::AddNumberPropInt64(env, value, "offset", jsPlayer->fileDescriptor_.offset);
1134 (void)CommonNapi::AddNumberPropInt64(env, value, "length", jsPlayer->fileDescriptor_.length);
1135
1136 MEDIA_LOGI("JsGetAVFileDescriptor Out");
1137 return value;
1138 }
1139
JsSetDataSrc(napi_env env,napi_callback_info info)1140 napi_value AVPlayerNapi::JsSetDataSrc(napi_env env, napi_callback_info info)
1141 {
1142 MediaTrace trace("AVPlayerNapi::set dataSrc");
1143 napi_value result = nullptr;
1144 napi_get_undefined(env, &result);
1145 MEDIA_LOGI("JsSetDataSrc In");
1146
1147 napi_value args[1] = { nullptr };
1148 size_t argCount = 1;
1149 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1150 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1151
1152 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_IDLE) {
1153 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is not idle, unsupport set dataSrc");
1154 return result;
1155 }
1156 jsPlayer->StartListenCurrentResource(); // Listen to the events of the current resource
1157
1158 napi_valuetype valueType = napi_undefined;
1159 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
1160 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "args[0] is not napi_object");
1161 return result;
1162 }
1163 (void)CommonNapi::GetPropertyInt64(env, args[0], "fileSize", jsPlayer->dataSrcDescriptor_.fileSize);
1164 if (jsPlayer->dataSrcDescriptor_.fileSize < -1 || jsPlayer->dataSrcDescriptor_.fileSize == 0) {
1165 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check parameter fileSize");
1166 return result;
1167 }
1168 MEDIA_LOGD("Recvive filesize is %{public}" PRId64 "", jsPlayer->dataSrcDescriptor_.fileSize);
1169 jsPlayer->dataSrcCb_ = std::make_shared<MediaDataSourceCallback>(env, jsPlayer->dataSrcDescriptor_.fileSize);
1170
1171 napi_value callback = nullptr;
1172 napi_ref ref = nullptr;
1173 napi_get_named_property(env, args[0], "callback", &callback);
1174 jsPlayer->dataSrcDescriptor_.callback = callback;
1175 napi_status status = napi_create_reference(env, callback, 1, &ref);
1176 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
1177 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
1178 jsPlayer->dataSrcCb_->SaveCallbackReference(READAT_CALLBACK_NAME, autoRef);
1179
1180 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1181 MEDIA_LOGI("SetDataSrc Task");
1182 if (jsPlayer->player_ != nullptr) {
1183 if (jsPlayer->player_->SetSource(jsPlayer->dataSrcCb_) != MSERR_OK) {
1184 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "player SetSource DataSrc failed");
1185 }
1186 if (jsPlayer->dataSrcDescriptor_.fileSize == -1) {
1187 jsPlayer->isLiveStream_ = true;
1188 }
1189 }
1190 });
1191 (void)jsPlayer->taskQue_->EnqueueTask(task);
1192
1193 MEDIA_LOGI("JsSetDataSrc Out");
1194 return result;
1195 }
1196
JsGetDataSrc(napi_env env,napi_callback_info info)1197 napi_value AVPlayerNapi::JsGetDataSrc(napi_env env, napi_callback_info info)
1198 {
1199 MediaTrace trace("AVPlayerNapi::get dataSrc");
1200 napi_value result = nullptr;
1201 napi_get_undefined(env, &result);
1202 MEDIA_LOGI("JsGetDataSrc In");
1203
1204 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1205 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1206 CHECK_AND_RETURN_RET_LOG(jsPlayer->dataSrcCb_ != nullptr, result, "failed to check dataSrcCb_");
1207
1208 napi_value value = nullptr;
1209 int64_t fileSize;
1210 napi_value callback = nullptr;
1211 (void)napi_create_object(env, &value);
1212 (void)jsPlayer->dataSrcCb_->GetSize(fileSize);
1213 (void)CommonNapi::AddNumberPropInt64(env, value, "fileSize", fileSize);
1214 int32_t ret = jsPlayer->dataSrcCb_->GetCallback(READAT_CALLBACK_NAME, &callback);
1215 CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, result, "failed to GetCallback");
1216 (void)MediaDataSourceCallback::AddNapiValueProp(env, value, "callback", callback);
1217
1218 MEDIA_LOGI("JsGetDataSrc Out");
1219 return value;
1220 }
1221
1222 #ifdef SUPPORT_VIDEO
SetSurface(const std::string & surfaceStr)1223 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
1224 {
1225 MEDIA_LOGI("get surface, surfaceStr = %{public}s", surfaceStr.c_str());
1226 uint64_t surfaceId = 0;
1227 if (surfaceStr.empty() || surfaceStr[0] < '0' || surfaceStr[0] > '9') {
1228 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1229 "Please obtain the surface from XComponentController.getXComponentSurfaceId");
1230 return;
1231 }
1232 surfaceId = std::stoull(surfaceStr);
1233 MEDIA_LOGI("get surface, surfaceId = (%{public}" PRIu64 ")", surfaceId);
1234
1235 auto surface = SurfaceUtils::GetInstance()->GetSurface(surfaceId);
1236 if (surface == nullptr) {
1237 OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SurfaceUtils cannot convert ID to Surface");
1238 return;
1239 }
1240
1241 auto task = std::make_shared<TaskHandler<void>>([this, surface]() {
1242 MEDIA_LOGI("SetSurface Task");
1243 if (player_ != nullptr) {
1244 (void)player_->SetVideoSurface(surface);
1245 }
1246 });
1247 (void)taskQue_->EnqueueTask(task);
1248 }
1249 #else
SetSurface(const std::string & surfaceStr)1250 void AVPlayerNapi::SetSurface(const std::string &surfaceStr)
1251 {
1252 (void)surfaceStr;
1253 OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The music player does not need to support (Surface)");
1254 }
1255 #endif
1256
JsSetSurfaceID(napi_env env,napi_callback_info info)1257 napi_value AVPlayerNapi::JsSetSurfaceID(napi_env env, napi_callback_info info)
1258 {
1259 MediaTrace trace("AVPlayerNapi::set surface");
1260 napi_value result = nullptr;
1261 napi_get_undefined(env, &result);
1262 MEDIA_LOGI("JsSetSurfaceID In");
1263
1264 napi_value args[1] = { nullptr };
1265 size_t argCount = 1; // surfaceId?: string
1266 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1267 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1268
1269 napi_valuetype valueType = napi_undefined;
1270 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
1271 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "the attribute(SurfaceID) input is not string");
1272 return result;
1273 }
1274
1275 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_INITIALIZED) {
1276 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1277 "the attribute(SurfaceID) can only be set in the initialized state");
1278 return result;
1279 }
1280
1281 // get url from js
1282 jsPlayer->surface_ = CommonNapi::GetStringArgument(env, args[0]);
1283 jsPlayer->SetSurface(jsPlayer->surface_);
1284 MEDIA_LOGI("JsSetSurfaceID Out");
1285 return result;
1286 }
1287
JsGetSurfaceID(napi_env env,napi_callback_info info)1288 napi_value AVPlayerNapi::JsGetSurfaceID(napi_env env, napi_callback_info info)
1289 {
1290 MediaTrace trace("AVPlayerNapi::get surface");
1291 napi_value result = nullptr;
1292 napi_get_undefined(env, &result);
1293 MEDIA_LOGI("JsGetSurfaceID In");
1294
1295 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1296 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1297
1298 napi_value value = nullptr;
1299 (void)napi_create_string_utf8(env, jsPlayer->surface_.c_str(), NAPI_AUTO_LENGTH, &value);
1300
1301 MEDIA_LOGI("JsGetSurfaceID Out Current SurfaceID: %{public}s", jsPlayer->surface_.c_str());
1302 return value;
1303 }
1304
JsSetLoop(napi_env env,napi_callback_info info)1305 napi_value AVPlayerNapi::JsSetLoop(napi_env env, napi_callback_info info)
1306 {
1307 MediaTrace trace("AVPlayerNapi::set loop");
1308 napi_value result = nullptr;
1309 napi_get_undefined(env, &result);
1310 MEDIA_LOGI("JsSetLoop In");
1311
1312 napi_value args[1] = { nullptr };
1313 size_t argCount = 1; // loop: boolenan
1314 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1315 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1316
1317 if (jsPlayer->IsLiveSource()) {
1318 jsPlayer->OnErrorCb(MSERR_EXT_API9_UNSUPPORT_CAPABILITY, "The stream is live stream, not support loop");
1319 return result;
1320 }
1321
1322 if (!jsPlayer->IsControllable()) {
1323 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1324 "current state is not prepared/playing/paused/completed, unsupport loop operation");
1325 return result;
1326 }
1327
1328 napi_valuetype valueType = napi_undefined;
1329 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_boolean) {
1330 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetLoop is not napi_boolean");
1331 return result;
1332 }
1333
1334 napi_status status = napi_get_value_bool(env, args[0], &jsPlayer->loop_);
1335 if (status != napi_ok) {
1336 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1337 "invalid parameters, please check the input loop");
1338 return result;
1339 }
1340
1341 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1342 MEDIA_LOGI("SetLooping Task");
1343 if (jsPlayer->player_ != nullptr) {
1344 (void)jsPlayer->player_->SetLooping(jsPlayer->loop_);
1345 }
1346 });
1347 (void)jsPlayer->taskQue_->EnqueueTask(task);
1348 MEDIA_LOGI("JsSetLoop Out");
1349 return result;
1350 }
1351
JsGetLoop(napi_env env,napi_callback_info info)1352 napi_value AVPlayerNapi::JsGetLoop(napi_env env, napi_callback_info info)
1353 {
1354 MediaTrace trace("AVPlayerNapi::get loop");
1355 napi_value result = nullptr;
1356 napi_get_undefined(env, &result);
1357 MEDIA_LOGI("JsGetLoop In");
1358
1359 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1360 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1361
1362 napi_value value = nullptr;
1363 (void)napi_get_boolean(env, jsPlayer->loop_, &value);
1364 MEDIA_LOGI("JsGetLoop Out Current Loop: %{public}d", jsPlayer->loop_);
1365 return value;
1366 }
1367
JsSetVideoScaleType(napi_env env,napi_callback_info info)1368 napi_value AVPlayerNapi::JsSetVideoScaleType(napi_env env, napi_callback_info info)
1369 {
1370 MediaTrace trace("AVPlayerNapi::set videoScaleType");
1371 napi_value result = nullptr;
1372 napi_get_undefined(env, &result);
1373 MEDIA_LOGI("JsSetVideoScaleType In");
1374
1375 napi_value args[1] = { nullptr };
1376 size_t argCount = 1;
1377 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1378 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1379
1380 if (!jsPlayer->IsControllable()) {
1381 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1382 "current state is not prepared/playing/paused/completed, unsupport video scale operation");
1383 return result;
1384 }
1385
1386 napi_valuetype valueType = napi_undefined;
1387 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1388 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetVideoScaleType is not napi_number");
1389 return result;
1390 }
1391
1392 int32_t videoScaleType = 0;
1393 napi_status status = napi_get_value_int32(env, args[0], &videoScaleType);
1394 if (status != napi_ok || videoScaleType < VIDEO_SCALE_TYPE_FIT || videoScaleType > VIDEO_SCALE_TYPE_FIT_CROP) {
1395 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input scale type");
1396 return result;
1397 }
1398 jsPlayer->videoScaleType_ = videoScaleType;
1399
1400 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, videoScaleType]() {
1401 MEDIA_LOGI("SetVideoScaleType Task");
1402 if (jsPlayer->player_ != nullptr) {
1403 Format format;
1404 (void)format.PutIntValue(PlayerKeys::VIDEO_SCALE_TYPE, videoScaleType);
1405 (void)jsPlayer->player_->SetParameter(format);
1406 }
1407 });
1408 (void)jsPlayer->taskQue_->EnqueueTask(task);
1409 MEDIA_LOGI("JsSetVideoScaleType Out");
1410 return result;
1411 }
1412
JsGetVideoScaleType(napi_env env,napi_callback_info info)1413 napi_value AVPlayerNapi::JsGetVideoScaleType(napi_env env, napi_callback_info info)
1414 {
1415 MediaTrace trace("AVPlayerNapi::get videoScaleType");
1416 napi_value result = nullptr;
1417 napi_get_undefined(env, &result);
1418 MEDIA_LOGI("JsGetVideoScaleType In");
1419
1420 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1421 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1422
1423 napi_value value = nullptr;
1424 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->videoScaleType_), &value);
1425 MEDIA_LOGI("JsGetVideoScaleType Out Current VideoScale: %{public}d", jsPlayer->videoScaleType_);
1426 return value;
1427 }
1428
JsSetAudioInterruptMode(napi_env env,napi_callback_info info)1429 napi_value AVPlayerNapi::JsSetAudioInterruptMode(napi_env env, napi_callback_info info)
1430 {
1431 MediaTrace trace("AVPlayerNapi::set audioInterruptMode");
1432 napi_value result = nullptr;
1433 napi_get_undefined(env, &result);
1434 MEDIA_LOGI("JsSetAudioInterruptMode In");
1435
1436 napi_value args[1] = { nullptr };
1437 size_t argCount = 1;
1438 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1439 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1440
1441 if (!jsPlayer->IsControllable()) {
1442 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1443 "current state is not prepared/playing/paused/completed, unsupport audio interrupt operation");
1444 return result;
1445 }
1446
1447 napi_valuetype valueType = napi_undefined;
1448 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1449 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "SetAudioInterruptMode is not napi_number");
1450 return result;
1451 }
1452
1453 int32_t interruptMode = 0;
1454 napi_status status = napi_get_value_int32(env, args[0], &interruptMode);
1455 if (status != napi_ok ||
1456 interruptMode < AudioStandard::InterruptMode::SHARE_MODE ||
1457 interruptMode > AudioStandard::InterruptMode::INDEPENDENT_MODE) {
1458 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1459 "invalid parameters, please check the input interrupt Mode");
1460 return result;
1461 }
1462 jsPlayer->interruptMode_ = static_cast<AudioStandard::InterruptMode>(interruptMode);
1463
1464 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1465 MEDIA_LOGI("SetAudioInterruptMode Task");
1466 if (jsPlayer->player_ != nullptr) {
1467 Format format;
1468 (void)format.PutIntValue(PlayerKeys::AUDIO_INTERRUPT_MODE, jsPlayer->interruptMode_);
1469 (void)jsPlayer->player_->SetParameter(format);
1470 }
1471 });
1472 (void)jsPlayer->taskQue_->EnqueueTask(task);
1473 MEDIA_LOGI("JsSetAudioInterruptMode Out");
1474 return result;
1475 }
1476
JsGetAudioInterruptMode(napi_env env,napi_callback_info info)1477 napi_value AVPlayerNapi::JsGetAudioInterruptMode(napi_env env, napi_callback_info info)
1478 {
1479 MediaTrace trace("AVPlayerNapi::get audioInterruptMode");
1480 napi_value result = nullptr;
1481 napi_get_undefined(env, &result);
1482 MEDIA_LOGI("JsGetAudioInterruptMode In");
1483
1484 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1485 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1486
1487 napi_value value = nullptr;
1488 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->interruptMode_), &value);
1489 MEDIA_LOGI("JsGetAudioInterruptMode Out");
1490 return value;
1491 }
1492
JsSetAudioEffectMode(napi_env env,napi_callback_info info)1493 napi_value AVPlayerNapi::JsSetAudioEffectMode(napi_env env, napi_callback_info info)
1494 {
1495 MediaTrace trace("AVPlayerNapi::JsSetAudioEffectMode");
1496 MEDIA_LOGI("JsSetAudioEffectMode In");
1497 napi_value result = nullptr;
1498 napi_get_undefined(env, &result);
1499
1500 size_t argCount = 1; // 1param audioEffectMode
1501 napi_value args[1] = { nullptr };
1502 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1503 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1504
1505 if (!jsPlayer->IsControllable()) {
1506 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1507 "current state is not prepared/playing/paused/completed, unsupport audio effect mode operation");
1508 return result;
1509 }
1510
1511 napi_valuetype valueType = napi_undefined;
1512 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1513 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "audioEffectMode is not number");
1514 return result;
1515 }
1516
1517 int32_t effectMode = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
1518 napi_status status = napi_get_value_int32(env, args[0], &effectMode);
1519 if (status != napi_ok || effectMode > OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT ||
1520 effectMode < OHOS::AudioStandard::AudioEffectMode::EFFECT_NONE) {
1521 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1522 "invalid audioEffectMode, please check the input audio effect Mode");
1523 return result;
1524 }
1525
1526 if (jsPlayer->audioEffectMode_ == effectMode) {
1527 MEDIA_LOGI("Same effectMode parameter");
1528 return result;
1529 }
1530
1531 jsPlayer->audioEffectMode_ = effectMode;
1532
1533 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, effectMode]() {
1534 MEDIA_LOGI("JsSetAudioEffectMode Task in");
1535 if (jsPlayer->player_ != nullptr) {
1536 Format format;
1537 (void)format.PutIntValue(PlayerKeys::AUDIO_EFFECT_MODE, effectMode);
1538 (void)jsPlayer->player_->SetParameter(format);
1539 }
1540 MEDIA_LOGI("JsSetAudioEffectMode Task out");
1541 });
1542 (void)jsPlayer->taskQue_->EnqueueTask(task);
1543 MEDIA_LOGI("JsSetAudioEffectMode Out");
1544 return result;
1545 }
1546
JsGetAudioEffectMode(napi_env env,napi_callback_info info)1547 napi_value AVPlayerNapi::JsGetAudioEffectMode(napi_env env, napi_callback_info info)
1548 {
1549 MediaTrace trace("AVPlayerNapi::JsGetAudioEffectMode");
1550 MEDIA_LOGI("JsGetAudioEffectMode In");
1551 napi_value result = nullptr;
1552 napi_get_undefined(env, &result);
1553
1554 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1555 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1556
1557 napi_value value = nullptr;
1558 (void)napi_create_int32(env, static_cast<int32_t>(jsPlayer->audioEffectMode_), &value);
1559 MEDIA_LOGI("JsGetAudioEffectMode Out");
1560 return value;
1561 }
1562
JsHandleParameter(napi_env env,napi_value args,AVPlayerNapi * jsPlayer)1563 bool AVPlayerNapi::JsHandleParameter(napi_env env, napi_value args, AVPlayerNapi *jsPlayer)
1564 {
1565 int32_t content = -1;
1566 int32_t usage = -1;
1567 int32_t rendererFlags = -1;
1568 (void)CommonNapi::GetPropertyInt32(env, args, "content", content);
1569 (void)CommonNapi::GetPropertyInt32(env, args, "usage", usage);
1570 (void)CommonNapi::GetPropertyInt32(env, args, "rendererFlags", rendererFlags);
1571 MEDIA_LOGI("content = %{public}d, usage = %{public}d, rendererFlags = %{public}d",
1572 content, usage, rendererFlags);
1573 std::vector<int32_t> contents = {
1574 CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_SPEECH,
1575 CONTENT_TYPE_MUSIC, CONTENT_TYPE_MOVIE,
1576 CONTENT_TYPE_SONIFICATION, CONTENT_TYPE_RINGTONE,
1577 CONTENT_TYPE_ULTRASONIC
1578 };
1579 std::vector<int32_t> usages = {
1580 STREAM_USAGE_UNKNOWN, STREAM_USAGE_MEDIA,
1581 STREAM_USAGE_VOICE_COMMUNICATION, STREAM_USAGE_VOICE_ASSISTANT,
1582 STREAM_USAGE_ALARM, STREAM_USAGE_NOTIFICATION_RINGTONE,
1583 STREAM_USAGE_RANGING, STREAM_USAGE_ACCESSIBILITY,
1584 STREAM_USAGE_SYSTEM
1585 };
1586 if (std::find(contents.begin(), contents.end(), content) == contents.end() ||
1587 std::find(usages.begin(), usages.end(), usage) == usages.end()) {
1588 return false;
1589 }
1590
1591 if (jsPlayer->audioRendererInfo_.contentType != content ||
1592 jsPlayer->audioRendererInfo_.streamUsage != usage) {
1593 jsPlayer->audioEffectMode_ = OHOS::AudioStandard::AudioEffectMode::EFFECT_DEFAULT;
1594 }
1595
1596 jsPlayer->audioRendererInfo_ = AudioStandard::AudioRendererInfo {
1597 static_cast<AudioStandard::ContentType>(content),
1598 static_cast<AudioStandard::StreamUsage>(usage),
1599 rendererFlags,
1600 };
1601 return true;
1602 }
1603
JsSetAudioRendererInfo(napi_env env,napi_callback_info info)1604 napi_value AVPlayerNapi::JsSetAudioRendererInfo(napi_env env, napi_callback_info info)
1605 {
1606 MediaTrace trace("AVPlayerNapi::set audioRendererInfo");
1607 napi_value result = nullptr;
1608 napi_get_undefined(env, &result);
1609 MEDIA_LOGI("JsSetAudioRendererInfo In");
1610
1611 napi_value args[1] = { nullptr };
1612 size_t argCount = 1;
1613 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1614 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1615 napi_valuetype valueType = napi_undefined;
1616 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
1617 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the input");
1618 return result;
1619 }
1620 if (jsPlayer->GetCurrentState() != AVPlayerState::STATE_INITIALIZED) {
1621 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1622 "current state is not initialized, unsupport to set audio renderer info");
1623 return result;
1624 }
1625 if (!AVPlayerNapi::JsHandleParameter(env, args[0], jsPlayer)) {
1626 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER,
1627 "invalid parameters, please check the input audio renderer info");
1628 return result;
1629 }
1630 auto task = std::make_shared<TaskHandler<void>>([jsPlayer]() {
1631 MEDIA_LOGI("SetAudioRendererInfo Task");
1632 if (jsPlayer->player_ != nullptr) {
1633 Format format;
1634 (void)format.PutIntValue(PlayerKeys::CONTENT_TYPE, jsPlayer->audioRendererInfo_.contentType);
1635 (void)format.PutIntValue(PlayerKeys::STREAM_USAGE, jsPlayer->audioRendererInfo_.streamUsage);
1636 (void)format.PutIntValue(PlayerKeys::RENDERER_FLAG, jsPlayer->audioRendererInfo_.rendererFlags);
1637 (void)jsPlayer->player_->SetParameter(format);
1638 }
1639 });
1640 (void)jsPlayer->taskQue_->EnqueueTask(task);
1641 MEDIA_LOGI("JsSetAudioRendererInfo Out");
1642 return result;
1643 }
1644
JsGetAudioRendererInfo(napi_env env,napi_callback_info info)1645 napi_value AVPlayerNapi::JsGetAudioRendererInfo(napi_env env, napi_callback_info info)
1646 {
1647 MediaTrace trace("AVPlayerNapi::get audioRendererInfo");
1648 napi_value result = nullptr;
1649 napi_get_undefined(env, &result);
1650 MEDIA_LOGI("JsGetAudioRendererInfo In");
1651
1652 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1653 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1654
1655 int32_t content = static_cast<int32_t>(jsPlayer->audioRendererInfo_.contentType);
1656 int32_t usage = static_cast<int32_t>(jsPlayer->audioRendererInfo_.streamUsage);
1657 int32_t rendererFlags = jsPlayer->audioRendererInfo_.rendererFlags;
1658 (void)napi_create_object(env, &result);
1659 CommonNapi::SetPropertyInt32(env, result, "content", content);
1660 CommonNapi::SetPropertyInt32(env, result, "usage", usage);
1661 CommonNapi::SetPropertyInt32(env, result, "rendererFlags", rendererFlags);
1662 MEDIA_LOGI("JsGetAudioRendererInfo Out");
1663 return result;
1664 }
1665
JsGetCurrentTime(napi_env env,napi_callback_info info)1666 napi_value AVPlayerNapi::JsGetCurrentTime(napi_env env, napi_callback_info info)
1667 {
1668 MediaTrace trace("AVPlayerNapi::get currentTime");
1669 napi_value result = nullptr;
1670 napi_get_undefined(env, &result);
1671 MEDIA_LOGI("JsGetCurrentTime In");
1672
1673 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1674 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1675
1676 int32_t currentTime = -1;
1677 if (jsPlayer->IsControllable()) {
1678 currentTime = jsPlayer->position_;
1679 }
1680
1681 if (jsPlayer->IsLiveSource() && jsPlayer->dataSrcCb_ == nullptr) {
1682 currentTime = -1;
1683 }
1684 napi_value value = nullptr;
1685 (void)napi_create_int32(env, currentTime, &value);
1686 std::string curState = jsPlayer->GetCurrentState();
1687 MEDIA_LOGI("JsGetCurrenTime Out, state %{public}s, time: %{public}d", curState.c_str(), currentTime);
1688 return value;
1689 }
1690
JsGetDuration(napi_env env,napi_callback_info info)1691 napi_value AVPlayerNapi::JsGetDuration(napi_env env, napi_callback_info info)
1692 {
1693 MediaTrace trace("AVPlayerNapi::get duration");
1694 napi_value result = nullptr;
1695 napi_get_undefined(env, &result);
1696 MEDIA_LOGI("JsGetDuration In");
1697
1698 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1699 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1700
1701 int32_t duration = -1;
1702 if (jsPlayer->IsControllable() && !jsPlayer->IsLiveSource()) {
1703 duration = jsPlayer->duration_;
1704 }
1705
1706 napi_value value = nullptr;
1707 (void)napi_create_int32(env, duration, &value);
1708 std::string curState = jsPlayer->GetCurrentState();
1709 MEDIA_LOGI("JsGetDuration Out, state %{public}s, duration %{public}d", curState.c_str(), duration);
1710 return value;
1711 }
1712
IsControllable()1713 bool AVPlayerNapi::IsControllable()
1714 {
1715 auto state = GetCurrentState();
1716 if (state == AVPlayerState::STATE_PREPARED || state == AVPlayerState::STATE_PLAYING ||
1717 state == AVPlayerState::STATE_PAUSED || state == AVPlayerState::STATE_COMPLETED) {
1718 return true;
1719 } else {
1720 return false;
1721 }
1722 }
1723
GetCurrentState()1724 std::string AVPlayerNapi::GetCurrentState()
1725 {
1726 if (isReleased_.load()) {
1727 return AVPlayerState::STATE_RELEASED;
1728 } else {
1729 std::string curState = AVPlayerState::STATE_ERROR;
1730 static const std::map<PlayerStates, std::string> stateMap = {
1731 {PLAYER_IDLE, AVPlayerState::STATE_IDLE},
1732 {PLAYER_INITIALIZED, AVPlayerState::STATE_INITIALIZED},
1733 {PLAYER_PREPARED, AVPlayerState::STATE_PREPARED},
1734 {PLAYER_STARTED, AVPlayerState::STATE_PLAYING},
1735 {PLAYER_PAUSED, AVPlayerState::STATE_PAUSED},
1736 {PLAYER_STOPPED, AVPlayerState::STATE_STOPPED},
1737 {PLAYER_PLAYBACK_COMPLETE, AVPlayerState::STATE_COMPLETED},
1738 {PLAYER_STATE_ERROR, AVPlayerState::STATE_ERROR},
1739 };
1740
1741 if (stateMap.find(state_) != stateMap.end()) {
1742 curState = stateMap.at(state_);
1743 }
1744 return curState;
1745 }
1746 }
1747
JsGetState(napi_env env,napi_callback_info info)1748 napi_value AVPlayerNapi::JsGetState(napi_env env, napi_callback_info info)
1749 {
1750 MediaTrace trace("AVPlayerNapi::get state");
1751 napi_value result = nullptr;
1752 napi_get_undefined(env, &result);
1753 MEDIA_LOGI("JsGetState In");
1754
1755 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1756 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1757
1758 std::string curState = jsPlayer->GetCurrentState();
1759 napi_value value = nullptr;
1760 (void)napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &value);
1761 MEDIA_LOGI("JsGetState Out");
1762 return value;
1763 }
1764
JsGetWidth(napi_env env,napi_callback_info info)1765 napi_value AVPlayerNapi::JsGetWidth(napi_env env, napi_callback_info info)
1766 {
1767 MediaTrace trace("AVPlayerNapi::get width");
1768 napi_value result = nullptr;
1769 napi_get_undefined(env, &result);
1770 MEDIA_LOGI("JsGetWidth In");
1771
1772 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1773 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1774
1775 int32_t width = 0;
1776 if (jsPlayer->IsControllable()) {
1777 width = jsPlayer->width_;
1778 }
1779
1780 napi_value value = nullptr;
1781 (void)napi_create_int32(env, width, &value);
1782 MEDIA_LOGI("JsGetWidth Out");
1783 return value;
1784 }
1785
JsGetHeight(napi_env env,napi_callback_info info)1786 napi_value AVPlayerNapi::JsGetHeight(napi_env env, napi_callback_info info)
1787 {
1788 MediaTrace trace("AVPlayerNapi::get height");
1789 napi_value result = nullptr;
1790 napi_get_undefined(env, &result);
1791 MEDIA_LOGI("JsGetHeight In");
1792
1793 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstance(env, info);
1794 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstance");
1795
1796 int32_t height = 0;
1797 if (jsPlayer->IsControllable()) {
1798 height = jsPlayer->height_;
1799 }
1800
1801 napi_value value = nullptr;
1802 (void)napi_create_int32(env, height, &value);
1803 MEDIA_LOGI("JsGetHeight Out");
1804 return value;
1805 }
1806
JsGetTrackDescription(napi_env env,napi_callback_info info)1807 napi_value AVPlayerNapi::JsGetTrackDescription(napi_env env, napi_callback_info info)
1808 {
1809 MediaTrace trace("AVPlayerNapi::get trackDescription");
1810 napi_value result = nullptr;
1811 napi_get_undefined(env, &result);
1812 MEDIA_LOGI("GetTrackDescription In");
1813
1814 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1815 napi_value args[1] = { nullptr };
1816 size_t argCount = 1;
1817 promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1818 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
1819 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
1820 // async work
1821 napi_value resource = nullptr;
1822 napi_create_string_utf8(env, "JsGetTrackDescription", NAPI_AUTO_LENGTH, &resource);
1823 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1824 [](napi_env env, void *data) {
1825 MEDIA_LOGI("GetTrackDescription Task");
1826 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1827 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1828
1829 auto jsPlayer = promiseCtx->napi;
1830 if (jsPlayer == nullptr) {
1831 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "avplayer is deconstructed");
1832 }
1833
1834 std::vector<Format> &trackInfo = jsPlayer->trackInfoVec_;
1835 trackInfo.clear();
1836 if (jsPlayer->IsControllable()) {
1837 (void)jsPlayer->player_->GetVideoTrackInfo(trackInfo);
1838 (void)jsPlayer->player_->GetAudioTrackInfo(trackInfo);
1839 (void)jsPlayer->player_->GetSubtitleTrackInfo(trackInfo);
1840 } else {
1841 return promiseCtx->SignError(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1842 "current state unsupport get track description");
1843 }
1844 promiseCtx->JsResult = std::make_unique<MediaJsResultArray>(trackInfo);
1845 },
1846 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1847 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1848 promiseCtx.release();
1849 MEDIA_LOGI("GetTrackDescription Out");
1850 return result;
1851 }
1852
JsSelectTrack(napi_env env,napi_callback_info info)1853 napi_value AVPlayerNapi::JsSelectTrack(napi_env env, napi_callback_info info)
1854 {
1855 MediaTrace trace("AVPlayerNapi::selectTrack");
1856 MEDIA_LOGI("JsSelectTrack In");
1857 napi_value result = nullptr;
1858 napi_get_undefined(env, &result);
1859
1860 size_t argCount = 1; // 1 prarm, args[0]:index
1861 napi_value args[1] = { nullptr };
1862 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1863 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1864
1865 napi_valuetype valueType = napi_undefined;
1866 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1867 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
1868 return result;
1869 }
1870
1871 int32_t index = -1;
1872 napi_status status = napi_get_value_int32(env, args[0], &index);
1873 if (status != napi_ok || index < 0) {
1874 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the track index");
1875 return result;
1876 }
1877
1878 if (!jsPlayer->IsControllable()) {
1879 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1880 "current state is not prepared/playing/paused/completed, unsupport selectTrack operation");
1881 return result;
1882 }
1883
1884 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, index]() {
1885 MEDIA_LOGI("selectTrack Task");
1886 if (jsPlayer->player_ != nullptr) {
1887 (void)jsPlayer->player_->SelectTrack(index);
1888 }
1889 MEDIA_LOGI("selectTrack Task end");
1890 });
1891 (void)jsPlayer->taskQue_->EnqueueTask(task);
1892 return result;
1893 }
1894
JsDeselectTrack(napi_env env,napi_callback_info info)1895 napi_value AVPlayerNapi::JsDeselectTrack(napi_env env, napi_callback_info info)
1896 {
1897 MediaTrace trace("AVPlayerNapi::deselectTrack");
1898 MEDIA_LOGI("deselectTrack In");
1899 napi_value result = nullptr;
1900 napi_get_undefined(env, &result);
1901
1902 size_t argCount = 1; // 1 prarm, args[0]:index
1903 napi_value args[1] = { nullptr };
1904 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1905 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
1906
1907 napi_valuetype valueType = napi_undefined;
1908 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_number) {
1909 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
1910 return result;
1911 }
1912
1913 int32_t index = -1;
1914 napi_status status = napi_get_value_int32(env, args[0], &index);
1915 if (status != napi_ok || index < 0) {
1916 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "invalid parameters, please check the track index");
1917 return result;
1918 }
1919
1920 if (!jsPlayer->IsControllable()) {
1921 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1922 "current state is not prepared/playing/paused/completed, unsupport deselecttrack operation");
1923 return result;
1924 }
1925
1926 auto task = std::make_shared<TaskHandler<void>>([jsPlayer, index]() {
1927 MEDIA_LOGI("deselectTrack Task");
1928 if (jsPlayer->player_ != nullptr) {
1929 (void)jsPlayer->player_->DeselectTrack(index);
1930 }
1931 MEDIA_LOGI("deselectTrack Task end");
1932 });
1933 (void)jsPlayer->taskQue_->EnqueueTask(task);
1934 return result;
1935 }
1936
JsGetCurrentTrack(napi_env env,napi_callback_info info)1937 napi_value AVPlayerNapi::JsGetCurrentTrack(napi_env env, napi_callback_info info)
1938 {
1939 MediaTrace trace("AVPlayerNapi::JsGetCurrentTrack");
1940 MEDIA_LOGI("GetCurrentTrack In");
1941 napi_value result = nullptr;
1942 napi_get_undefined(env, &result);
1943
1944 size_t argCount = 2; // 2 param: trackType + callback
1945 napi_value args[2] = { nullptr };
1946 auto promiseCtx = std::make_unique<AVPlayerContext>(env);
1947 promiseCtx->napi = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
1948 CHECK_AND_RETURN_RET_LOG(promiseCtx->napi != nullptr, result, "failed to GetJsInstanceWithParameter");
1949 promiseCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
1950 promiseCtx->deferred = CommonNapi::CreatePromise(env, promiseCtx->callbackRef, result);
1951
1952 promiseCtx->napi->GetCurrentTrackTask(promiseCtx, env, args[0]);
1953
1954 // async work
1955 napi_value resource = nullptr;
1956 napi_create_string_utf8(env, "JsGetCurrentTrack", NAPI_AUTO_LENGTH, &resource);
1957 NAPI_CALL(env, napi_create_async_work(env, nullptr, resource,
1958 [](napi_env env, void *data) {
1959 MEDIA_LOGI("GetCurrentTrack Task");
1960 auto promiseCtx = reinterpret_cast<AVPlayerContext *>(data);
1961 CHECK_AND_RETURN_LOG(promiseCtx != nullptr, "promiseCtx is nullptr!");
1962 CHECK_AND_RETURN_LOG(promiseCtx->asyncTask != nullptr, "asyncTask is nullptr!");
1963 auto result = promiseCtx->asyncTask->GetResult();
1964 if (result.HasResult() && result.Value().first != MSERR_EXT_API9_OK) {
1965 promiseCtx->SignError(result.Value().first, result.Value().second);
1966 } else {
1967 promiseCtx->JsResult = std::make_unique<MediaJsResultInt>(stoi(result.Value().second));
1968 }
1969 MEDIA_LOGI("GetCurrentTrack Task end");
1970 },
1971 MediaAsyncContext::CompleteCallback, static_cast<void *>(promiseCtx.get()), &promiseCtx->work));
1972 napi_queue_async_work_with_qos(env, promiseCtx->work, napi_qos_user_initiated);
1973 promiseCtx.release();
1974 return result;
1975 }
1976
GetCurrentTrackTask(std::unique_ptr<AVPlayerContext> & promiseCtx,napi_env env,napi_value args)1977 void AVPlayerNapi::GetCurrentTrackTask(std::unique_ptr<AVPlayerContext> &promiseCtx, napi_env env, napi_value args)
1978 {
1979 if (!promiseCtx->napi->IsControllable()) {
1980 promiseCtx->napi->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
1981 "current state is not prepared/playing/paused/completed, unsupport getCurrentTrack operation");
1982 return;
1983 }
1984
1985 napi_valuetype valueType = napi_undefined;
1986 if (args == nullptr || napi_typeof(env, args, &valueType) != napi_ok || valueType != napi_number) {
1987 promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "track index is not number");
1988 return;
1989 }
1990
1991 int32_t trackType = MediaType::MEDIA_TYPE_AUD;
1992 napi_status status = napi_get_value_int32(env, args, &trackType);
1993 if (status != napi_ok || trackType < MediaType::MEDIA_TYPE_AUD || trackType > MediaType::MEDIA_TYPE_VID) {
1994 promiseCtx->SignError(MSERR_EXT_API9_INVALID_PARAMETER, "invalid track Type");
1995 return;
1996 }
1997
1998 auto task = std::make_shared<TaskHandler<TaskRet>>([this, trackType]() {
1999 MEDIA_LOGI("GetCurrentTrack Task In");
2000 std::unique_lock<std::mutex> lock(taskMutex_);
2001 CHECK_AND_RETURN_RET(IsControllable(), TaskRet(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
2002 "current state is not prepared/playing/paused/completed, unsupport getCurrentTrack operation"));
2003
2004 int32_t index = 0;
2005 int32_t ret = player_->GetCurrentTrack(trackType, index);
2006 if (ret != MSERR_OK) {
2007 auto errCode = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(ret));
2008 return TaskRet(errCode, "failed to GetCurrentTrack");
2009 }
2010 MEDIA_LOGI("GetCurrentTrack Task Out");
2011 return TaskRet(MSERR_EXT_API9_OK, std::to_string(index));
2012 });
2013 (void)taskQue_->EnqueueTask(task);
2014 promiseCtx->asyncTask = task;
2015 return;
2016 }
2017
JsSetOnCallback(napi_env env,napi_callback_info info)2018 napi_value AVPlayerNapi::JsSetOnCallback(napi_env env, napi_callback_info info)
2019 {
2020 MediaTrace trace("AVPlayerNapi::on");
2021 napi_value result = nullptr;
2022 napi_get_undefined(env, &result);
2023 MEDIA_LOGI("JsSetOnCallback In");
2024
2025 napi_value args[2] = { nullptr }; // args[0]:type, args[1]:callback
2026 size_t argCount = 2; // args[0]:type, args[1]:callback
2027 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2028 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2029
2030 if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
2031 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to on event");
2032 return result;
2033 }
2034
2035 napi_valuetype valueType0 = napi_undefined;
2036 napi_valuetype valueType1 = napi_undefined;
2037 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string ||
2038 args[1] == nullptr || napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
2039 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "napi_typeof failed, please check the input parameters");
2040 return result;
2041 }
2042
2043 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
2044 MEDIA_LOGI("set callbackName: %{public}s", callbackName.c_str());
2045
2046 napi_ref ref = nullptr;
2047 napi_status status = napi_create_reference(env, args[1], 1, &ref);
2048 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
2049
2050 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
2051 jsPlayer->SaveCallbackReference(callbackName, autoRef);
2052
2053 MEDIA_LOGI("JsSetOnCallback Out");
2054 return result;
2055 }
2056
JsClearOnCallback(napi_env env,napi_callback_info info)2057 napi_value AVPlayerNapi::JsClearOnCallback(napi_env env, napi_callback_info info)
2058 {
2059 MediaTrace trace("AVPlayerNapi::off");
2060 napi_value result = nullptr;
2061 napi_get_undefined(env, &result);
2062 MEDIA_LOGI("JsClearOnCallback In");
2063
2064 napi_value args[2] = { nullptr }; // args[0]:type, args[1]:callback
2065 size_t argCount = 2; // args[0]:type, args[1]:callback
2066 AVPlayerNapi *jsPlayer = AVPlayerNapi::GetJsInstanceWithParameter(env, info, argCount, args);
2067 CHECK_AND_RETURN_RET_LOG(jsPlayer != nullptr, result, "failed to GetJsInstanceWithParameter");
2068
2069 if (jsPlayer->GetCurrentState() == AVPlayerState::STATE_RELEASED) {
2070 jsPlayer->OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, "current state is released, unsupport to off event");
2071 return result;
2072 }
2073
2074 napi_valuetype valueType0 = napi_undefined;
2075 if (args[0] == nullptr || napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string) {
2076 jsPlayer->OnErrorCb(MSERR_EXT_API9_INVALID_PARAMETER, "napi_typeof failed, please check the input parameters");
2077 return result;
2078 }
2079
2080 std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
2081 MEDIA_LOGI("set callbackName: %{public}s", callbackName.c_str());
2082
2083 jsPlayer->ClearCallbackReference(callbackName);
2084 MEDIA_LOGI("JsClearOnCallback Out");
2085 return result;
2086 }
2087
SaveCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)2088 void AVPlayerNapi::SaveCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
2089 {
2090 std::lock_guard<std::mutex> lock(mutex_);
2091 refMap_[callbackName] = ref;
2092 if (playerCb_ != nullptr) {
2093 playerCb_->SaveCallbackReference(callbackName, ref);
2094 }
2095 }
2096
ClearCallbackReference()2097 void AVPlayerNapi::ClearCallbackReference()
2098 {
2099 std::lock_guard<std::mutex> lock(mutex_);
2100 if (playerCb_ != nullptr) {
2101 playerCb_->ClearCallbackReference();
2102 }
2103 refMap_.clear();
2104 }
2105
ClearCallbackReference(const std::string & callbackName)2106 void AVPlayerNapi::ClearCallbackReference(const std::string &callbackName)
2107 {
2108 std::lock_guard<std::mutex> lock(mutex_);
2109 if (playerCb_ != nullptr) {
2110 playerCb_->ClearCallbackReference(callbackName);
2111 }
2112 refMap_.erase(callbackName);
2113 }
2114
NotifyDuration(int32_t duration)2115 void AVPlayerNapi::NotifyDuration(int32_t duration)
2116 {
2117 duration_ = duration;
2118 }
2119
NotifyPosition(int32_t position)2120 void AVPlayerNapi::NotifyPosition(int32_t position)
2121 {
2122 position_ = position;
2123 }
2124
NotifyState(PlayerStates state)2125 void AVPlayerNapi::NotifyState(PlayerStates state)
2126 {
2127 std::lock_guard<std::mutex> lock(taskMutex_);
2128 if (state_ != state) {
2129 state_ = state;
2130 MEDIA_LOGI("notify %{public}s", GetCurrentState().c_str());
2131 stopWait_ = true;
2132 stateChangeCond_.notify_all();
2133 }
2134 }
2135
NotifyVideoSize(int32_t width,int32_t height)2136 void AVPlayerNapi::NotifyVideoSize(int32_t width, int32_t height)
2137 {
2138 width_ = width;
2139 height_ = height;
2140 }
2141
NotifyIsLiveStream()2142 void AVPlayerNapi::NotifyIsLiveStream()
2143 {
2144 isLiveStream_ = true;
2145 }
2146
ResetUserParameters()2147 void AVPlayerNapi::ResetUserParameters()
2148 {
2149 url_.clear();
2150 fileDescriptor_.fd = 0;
2151 fileDescriptor_.offset = 0;
2152 fileDescriptor_.length = -1;
2153 width_ = 0;
2154 height_ = 0;
2155 position_ = -1;
2156 duration_ = -1;
2157 loop_ = false;
2158 }
2159
StartListenCurrentResource()2160 void AVPlayerNapi::StartListenCurrentResource()
2161 {
2162 std::lock_guard<std::mutex> lock(mutex_);
2163 if (playerCb_ != nullptr) {
2164 playerCb_->Start();
2165 }
2166 }
2167
PauseListenCurrentResource()2168 void AVPlayerNapi::PauseListenCurrentResource()
2169 {
2170 std::lock_guard<std::mutex> lock(mutex_);
2171 if (playerCb_ != nullptr) {
2172 playerCb_->Pause();
2173 }
2174 }
2175
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)2176 void AVPlayerNapi::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
2177 {
2178 std::lock_guard<std::mutex> lock(mutex_);
2179 if (playerCb_ != nullptr) {
2180 playerCb_->OnErrorCb(errorCode, errorMsg);
2181 }
2182 }
2183
GetJsInstance(napi_env env,napi_callback_info info)2184 AVPlayerNapi* AVPlayerNapi::GetJsInstance(napi_env env, napi_callback_info info)
2185 {
2186 size_t argCount = 0;
2187 napi_value jsThis = nullptr;
2188 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
2189 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
2190
2191 AVPlayerNapi *jsPlayer = nullptr;
2192 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
2193 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
2194
2195 return jsPlayer;
2196 }
2197
GetJsInstanceWithParameter(napi_env env,napi_callback_info info,size_t & argc,napi_value * argv)2198 AVPlayerNapi* AVPlayerNapi::GetJsInstanceWithParameter(napi_env env, napi_callback_info info,
2199 size_t &argc, napi_value *argv)
2200 {
2201 napi_value jsThis = nullptr;
2202 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
2203 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
2204
2205 AVPlayerNapi *jsPlayer = nullptr;
2206 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&jsPlayer));
2207 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsPlayer != nullptr, nullptr, "failed to napi_unwrap");
2208
2209 return jsPlayer;
2210 }
2211
IsLiveSource() const2212 bool AVPlayerNapi::IsLiveSource() const
2213 {
2214 return isLiveStream_;
2215 }
2216 } // namespace Media
2217 } // namespace OHOS