• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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