• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "video_recorder_napi.h"
17 #include "recorder_callback_napi.h"
18 #include "media_log.h"
19 #include "media_errors.h"
20 #include "common_napi.h"
21 #include "directory_ex.h"
22 #include "string_ex.h"
23 #include "surface_utils.h"
24 #include "recorder_napi_utils.h"
25 #ifdef SUPPORT_JSSTACK
26 #include "xpower_event_js.h"
27 #endif
28 
29 namespace {
30     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_RECORDER, "VideoRecorderNapi"};
31 }
32 
33 namespace OHOS {
34 namespace Media {
35 thread_local napi_ref VideoRecorderNapi::constructor_ = nullptr;
36 const std::string CLASS_NAME = "VideoRecorder";
37 
VideoRecorderNapi()38 VideoRecorderNapi::VideoRecorderNapi()
39 {
40     MEDIA_LOGD("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
41 }
42 
~VideoRecorderNapi()43 VideoRecorderNapi::~VideoRecorderNapi()
44 {
45     CancelCallback();
46     recorder_ = nullptr;
47     callbackNapi_ = nullptr;
48     MEDIA_LOGD("0x%{public}06" PRIXPTR "Instances destroy", FAKE_POINTER(this));
49 }
50 
SignError(VideoRecorderAsyncContext * asyncCtx,int32_t code,const std::string & param1,const std::string & param2,const std::string & add="")51 static void SignError(VideoRecorderAsyncContext *asyncCtx, int32_t code,
52     const std::string &param1, const std::string &param2, const std::string &add = "")
53 {
54     std::string message = MSExtErrorAPI9ToString(static_cast<MediaServiceExtErrCodeAPI9>(code), param1, param2) + add;
55     asyncCtx->SignError(code, message);
56 }
57 
Init(napi_env env,napi_value exports)58 napi_value VideoRecorderNapi::Init(napi_env env, napi_value exports)
59 {
60     napi_property_descriptor properties[] = {
61         DECLARE_NAPI_FUNCTION("prepare", Prepare),
62         DECLARE_NAPI_FUNCTION("getInputSurface", GetInputSurface),
63         DECLARE_NAPI_FUNCTION("start", Start),
64         DECLARE_NAPI_FUNCTION("pause", Pause),
65         DECLARE_NAPI_FUNCTION("resume", Resume),
66         DECLARE_NAPI_FUNCTION("stop", Stop),
67         DECLARE_NAPI_FUNCTION("reset", Reset),
68         DECLARE_NAPI_FUNCTION("release", Release),
69         DECLARE_NAPI_FUNCTION("on", On),
70 
71         DECLARE_NAPI_GETTER("state", GetState),
72     };
73 
74     napi_property_descriptor staticProperty[] = {
75         DECLARE_NAPI_STATIC_FUNCTION("createVideoRecorder", CreateVideoRecorder),
76     };
77 
78     napi_value constructor = nullptr;
79     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
80         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
81     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define VideoRecorder class");
82 
83     status = napi_create_reference(env, constructor, 1, &constructor_);
84     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
85 
86     status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
87     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
88 
89     status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
90     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
91 
92     MEDIA_LOGD("Init success");
93 
94     return exports;
95 }
96 
Constructor(napi_env env,napi_callback_info info)97 napi_value VideoRecorderNapi::Constructor(napi_env env, napi_callback_info info)
98 {
99     napi_value result = nullptr;
100     napi_get_undefined(env, &result);
101 
102     napi_value jsThis = nullptr;
103     size_t argCount = 0;
104     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
105     if (status != napi_ok) {
106         MEDIA_LOGE ("Failed to retrieve details about the callback");
107         return result;
108     }
109 
110     VideoRecorderNapi *recorderNapi = new(std::nothrow) VideoRecorderNapi();
111     CHECK_AND_RETURN_RET_LOG(recorderNapi != nullptr, result, "No memory!");
112 
113     recorderNapi->env_ = env;
114     recorderNapi->recorder_ = RecorderFactory::CreateRecorder();
115     if (recorderNapi->recorder_ == nullptr) {
116         delete recorderNapi;
117         MEDIA_LOGE("failed to CreateRecorder");
118         return result;
119     }
120 
121     if (recorderNapi->callbackNapi_ == nullptr && recorderNapi->recorder_ != nullptr) {
122         recorderNapi->callbackNapi_ = std::make_shared<RecorderCallbackNapi>(env, true);
123         (void)recorderNapi->recorder_->SetRecorderCallback(recorderNapi->callbackNapi_);
124     }
125 
126     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(recorderNapi),
127         VideoRecorderNapi::Destructor, nullptr, nullptr);
128     if (status != napi_ok) {
129         delete recorderNapi;
130         MEDIA_LOGE("Failed to warp native instance!");
131         return result;
132     }
133 
134     MEDIA_LOGD("Constructor success");
135     return jsThis;
136 }
137 
Destructor(napi_env env,void * nativeObject,void * finalize)138 void VideoRecorderNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
139 {
140     (void)env;
141     (void)finalize;
142     if (nativeObject != nullptr) {
143         VideoRecorderNapi *napi = reinterpret_cast<VideoRecorderNapi *>(nativeObject);
144         if (napi->surface_ != nullptr) {
145             auto id = napi->surface_->GetUniqueId();
146             if (napi->IsSurfaceIdVaild(id)) {
147                 (void)SurfaceUtils::GetInstance()->Remove(id);
148             }
149         }
150         delete napi;
151     }
152     MEDIA_LOGD("Destructor success");
153 }
154 
CreateVideoRecorder(napi_env env,napi_callback_info info)155 napi_value VideoRecorderNapi::CreateVideoRecorder(napi_env env, napi_callback_info info)
156 {
157     MEDIA_LOGD("CreateVideoRecorder In");
158 
159     napi_value result = nullptr;
160     napi_get_undefined(env, &result);
161 
162     // get args
163     napi_value jsThis = nullptr;
164     napi_value args[1] = { nullptr };
165     size_t argCount = 1;
166     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
167     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
168 
169     std::unique_ptr<VideoRecorderAsyncContext> asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
170     if (!SystemPermission()) {
171         SignError(asyncCtx.get(),
172             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
173     }
174     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
175     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
176     asyncCtx->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
177     asyncCtx->ctorFlag = true;
178 
179     auto ret = MediaAsyncContext::SendCompleteEvent(env, asyncCtx.get(), napi_eprio_immediate);
180     if (ret != napi_status::napi_ok) {
181         MEDIA_LOGE("failed to SendEvent, ret = %{public}d", ret);
182     }
183     asyncCtx.release();
184 
185     MEDIA_LOGD("CreateVideoRecorder Out");
186 
187     return result;
188 }
189 
Prepare(napi_env env,napi_callback_info info)190 napi_value VideoRecorderNapi::Prepare(napi_env env, napi_callback_info info)
191 {
192     MEDIA_LOGD("VideoRecorderNapi Prepare In");
193 
194     napi_value result = nullptr;
195     napi_get_undefined(env, &result);
196     napi_value jsThis = nullptr;
197     napi_value args[2] = { nullptr };
198 
199     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
200 
201     if (!SystemPermission()) {
202         SignError(asyncCtx.get(),
203             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
204     }
205 
206     size_t argCount = 2;
207     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
208     if (status != napi_ok || jsThis == nullptr) {
209         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "prepare", "", "get parameters failed.");
210     }
211 
212     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
213 
214     napi_valuetype valueType = napi_undefined;
215     if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
216         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "prepare", "",
217             "config type should be VideoRecorderConfig.");
218     }
219 
220     std::string urlPath = CommonNapi::GetPropertyString(env, args[0], "url");
221 
222     VideoRecorderProperties videoProperties;
223 
224     asyncCtx->napi->GetConfig(env, args[0], asyncCtx, videoProperties);
225 
226     if (asyncCtx->napi->GetVideoRecorderProperties(env, args[0], videoProperties) != MSERR_OK) {
227         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "prepare", "", "get videoProperties failed.");
228     }
229 
230     if (asyncCtx->napi->SetVideoRecorderProperties(asyncCtx, videoProperties) != MSERR_OK) {
231         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "prepare", "", "set videoProperties failed.");
232     }
233     if (asyncCtx->napi->SetUrl(urlPath) != MSERR_OK) {
234         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "urlPath", "", "the url is not valid.");
235     }
236 
237     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[1]);
238     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
239 
240     asyncCtx->napi->currentStates_ = VideoRecorderState::STATE_PREPARED;
241     napi_value resource = nullptr;
242     napi_create_string_utf8(env, "Prepare", NAPI_AUTO_LENGTH, &resource);
243     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
244         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
245         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
246         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
247             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "prepare", "");
248             return;
249         }
250 
251         if (threadCtx->napi->recorder_->Prepare() != MSERR_OK) {
252             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "prepare", "");
253         }
254     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
255     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
256     asyncCtx.release();
257     return result;
258 }
259 
GetInputSurface(napi_env env,napi_callback_info info)260 napi_value VideoRecorderNapi::GetInputSurface(napi_env env, napi_callback_info info)
261 {
262     MEDIA_LOGD("GetInputSurface In");
263 
264     napi_value result = nullptr;
265     napi_get_undefined(env, &result);
266 
267     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
268 
269     if (!SystemPermission()) {
270         SignError(asyncCtx.get(),
271             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
272     }
273 
274     // get args
275     napi_value jsThis = nullptr;
276     napi_value args[1] = {nullptr};
277     size_t argCount = 1;
278     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
279     if (status != napi_ok || jsThis == nullptr) {
280         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "GetInputSurface", "");
281     }
282 
283     // get recordernapi
284     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
285 
286     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
287     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
288 
289     napi_value resource = nullptr;
290     napi_create_string_utf8(env, "GetInputSurface", NAPI_AUTO_LENGTH, &resource);
291     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
292         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
293         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
294         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
295             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "GetInputSurface", "");
296             return;
297         }
298 
299         threadCtx->napi->surface_ = threadCtx->napi->recorder_->GetSurface(threadCtx->napi->videoSourceID); // source id
300         if (threadCtx->napi->surface_ != nullptr) {
301             SurfaceError error = SurfaceUtils::GetInstance()->Add(threadCtx->napi->surface_->GetUniqueId(),
302                 threadCtx->napi->surface_);
303             if (error != SURFACE_ERROR_OK) {
304                 SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "GetInputSurface", "");
305             }
306             auto surfaceId = std::to_string(threadCtx->napi->surface_->GetUniqueId());
307             threadCtx->JsResult = std::make_unique<MediaJsResultString>(surfaceId);
308         } else {
309             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "GetInputSurface", "");
310         }
311     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
312     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
313     asyncCtx.release();
314     return result;
315 }
316 
Start(napi_env env,napi_callback_info info)317 napi_value VideoRecorderNapi::Start(napi_env env, napi_callback_info info)
318 {
319     MEDIA_LOGD("VideoRecorderNapi::Start In");
320 
321     napi_value result = nullptr;
322     napi_get_undefined(env, &result);
323 
324     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
325 
326     if (!SystemPermission()) {
327         SignError(asyncCtx.get(),
328             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
329     }
330 
331     napi_value jsThis = nullptr;
332     napi_value args[1] = { nullptr };
333     size_t argCount = 1;
334     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
335     if (status != napi_ok || jsThis == nullptr) {
336         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Start", "");
337     }
338 
339     // get recordernapi
340     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
341 
342     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
343     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
344 #ifdef SUPPORT_JSSTACK
345     HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
346 #endif
347     // async work
348     napi_value resource = nullptr;
349     napi_create_string_utf8(env, "Start", NAPI_AUTO_LENGTH, &resource);
350     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
351         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
352         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
353         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
354             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Start", "");
355             return;
356         }
357         if (threadCtx->napi->recorder_->Start() != MSERR_OK) {
358             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Start", "");
359         }
360         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_PLAYING;
361     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
362     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
363     asyncCtx.release();
364     return result;
365 }
366 
Pause(napi_env env,napi_callback_info info)367 napi_value VideoRecorderNapi::Pause(napi_env env, napi_callback_info info)
368 {
369     MEDIA_LOGD("Pause In");
370 
371     napi_value result = nullptr;
372     napi_get_undefined(env, &result);
373 
374     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
375 
376     if (!SystemPermission()) {
377         SignError(asyncCtx.get(),
378             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
379     }
380 
381     napi_value jsThis = nullptr;
382     napi_value args[1] = { nullptr };
383     size_t argCount = 1;
384     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
385     if (status != napi_ok || jsThis == nullptr) {
386         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Pause", "");
387     }
388 
389     // get recordernapi
390     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
391 
392     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
393     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
394 
395     // async work
396     napi_value resource = nullptr;
397     napi_create_string_utf8(env, "Pause", NAPI_AUTO_LENGTH, &resource);
398     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
399         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
400         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
401         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
402             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Pause", "");
403             return;
404         }
405         if (threadCtx->napi->recorder_->Pause() != MSERR_OK) {
406             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Pause", "");
407         }
408         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_PAUSED;
409     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
410     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
411     asyncCtx.release();
412     return result;
413 }
414 
Resume(napi_env env,napi_callback_info info)415 napi_value VideoRecorderNapi::Resume(napi_env env, napi_callback_info info)
416 {
417     MEDIA_LOGD("VideoRecorderNapi::Resume In");
418 
419     napi_value result = nullptr;
420     napi_get_undefined(env, &result);
421 
422     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
423 
424     if (!SystemPermission()) {
425         SignError(asyncCtx.get(),
426             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
427     }
428 
429     napi_value jsThis = nullptr;
430     napi_value args[1] = { nullptr };
431     size_t argCount = 1;
432     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
433     if (status != napi_ok || jsThis == nullptr) {
434         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Resume", "");
435     }
436 
437     // get recordernapi
438     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
439 
440     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
441     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
442 #ifdef SUPPORT_JSSTACK
443     HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
444 #endif
445     // async work
446     napi_value resource = nullptr;
447     napi_create_string_utf8(env, "Resume", NAPI_AUTO_LENGTH, &resource);
448     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
449         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
450         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
451         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
452             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Resume", "");
453             return;
454         }
455         if (threadCtx->napi->recorder_->Resume() != MSERR_OK) {
456             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Resume", "");
457         }
458         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_PLAYING;
459     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
460     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
461     asyncCtx.release();
462     return result;
463 }
464 
Stop(napi_env env,napi_callback_info info)465 napi_value VideoRecorderNapi::Stop(napi_env env, napi_callback_info info)
466 {
467     MEDIA_LOGD("Stop In");
468 
469     napi_value result = nullptr;
470     napi_get_undefined(env, &result);
471 
472     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
473 
474     if (!SystemPermission()) {
475         SignError(asyncCtx.get(),
476             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
477     }
478 
479     napi_value jsThis = nullptr;
480     napi_value args[1] = { nullptr };
481     size_t argCount = 1;
482     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
483     if (status != napi_ok || jsThis == nullptr) {
484         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Stop", "");
485     }
486 
487     // get recordernapi
488     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
489 
490     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
491     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
492 
493     // async work
494     napi_value resource = nullptr;
495     napi_create_string_utf8(env, "Stop", NAPI_AUTO_LENGTH, &resource);
496     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
497         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
498         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
499         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
500             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Stop", "");
501             return;
502         }
503         if (threadCtx->napi->recorder_->Stop(false) != MSERR_OK) {
504             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Stop", "");
505         }
506         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_STOPPED;
507     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
508     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
509     asyncCtx.release();
510     return result;
511 }
512 
Reset(napi_env env,napi_callback_info info)513 napi_value VideoRecorderNapi::Reset(napi_env env, napi_callback_info info)
514 {
515     MEDIA_LOGD("Reset In");
516 
517     napi_value result = nullptr;
518     napi_get_undefined(env, &result);
519 
520     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
521 
522     if (!SystemPermission()) {
523         SignError(asyncCtx.get(),
524             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
525     }
526 
527     napi_value jsThis = nullptr;
528     napi_value args[1] = { nullptr };
529     size_t argCount = 1;
530     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
531     if (status != napi_ok || jsThis == nullptr) {
532         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Reset", "");
533     }
534 
535     // get recordernapi
536     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
537 
538     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
539     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
540 
541     // async work
542     napi_value resource = nullptr;
543     napi_create_string_utf8(env, "Reset", NAPI_AUTO_LENGTH, &resource);
544     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {
545         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
546         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
547         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
548             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Reset", "");
549             return;
550         }
551         if (threadCtx->napi->surface_ != nullptr) {
552             auto id = threadCtx->napi->surface_->GetUniqueId();
553             if (threadCtx->napi->IsSurfaceIdVaild(id)) {
554                 (void)SurfaceUtils::GetInstance()->Remove(id);
555             }
556             threadCtx->napi->surface_ = nullptr;
557         }
558         if (threadCtx->napi->recorder_->Reset() != MSERR_OK) {
559             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Reset", "");
560         }
561         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_IDLE;
562     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
563     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
564     asyncCtx.release();
565     return result;
566 }
567 
Release(napi_env env,napi_callback_info info)568 napi_value VideoRecorderNapi::Release(napi_env env, napi_callback_info info)
569 {
570     MEDIA_LOGD("Release In");
571 
572     napi_value result = nullptr;
573     napi_get_undefined(env, &result);
574 
575     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
576 
577     if (!SystemPermission()) {
578         SignError(asyncCtx.get(),
579             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
580     }
581 
582     napi_value jsThis = nullptr;
583     napi_value args[1] = { nullptr };
584     size_t argCount = 1;
585     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
586     if (status != napi_ok || jsThis == nullptr) {
587         SignError(asyncCtx.get(), MSERR_EXT_API9_INVALID_PARAMETER, "Release", "");
588     }
589 
590     // get recordernapi
591     (void)napi_unwrap(env, jsThis, reinterpret_cast<void **>(&asyncCtx->napi));
592 
593     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
594     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
595 
596     // async work
597     napi_value resource = nullptr;
598     napi_create_string_utf8(env, "Release", NAPI_AUTO_LENGTH, &resource);
599     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void *data) {
600         auto threadCtx = reinterpret_cast<VideoRecorderAsyncContext *>(data);
601         CHECK_AND_RETURN_LOG(threadCtx != nullptr, "threadCtx is nullptr!");
602         if (threadCtx->napi == nullptr || threadCtx->napi->recorder_ == nullptr) {
603             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Release", "");
604             return;
605         }
606         if (threadCtx->napi->surface_ != nullptr) {
607             auto id = threadCtx->napi->surface_->GetUniqueId();
608             if (threadCtx->napi->IsSurfaceIdVaild(id)) {
609                 (void)SurfaceUtils::GetInstance()->Remove(id);
610             }
611             threadCtx->napi->surface_ = nullptr;
612         }
613         if (threadCtx->napi->recorder_->Release() != MSERR_OK) {
614             SignError(threadCtx, MSERR_EXT_API9_OPERATE_NOT_PERMIT, "Release", "");
615         }
616         threadCtx->napi->currentStates_ = VideoRecorderState::STATE_IDLE;
617         threadCtx->napi->CancelCallback();
618     }, MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
619     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
620     asyncCtx.release();
621     return result;
622 }
623 
On(napi_env env,napi_callback_info info)624 napi_value VideoRecorderNapi::On(napi_env env, napi_callback_info info)
625 {
626     napi_value result = nullptr;
627     napi_get_undefined(env, &result);
628 
629     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
630 
631     if (!SystemPermission()) {
632         SignError(asyncCtx.get(),
633             MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder", "system");
634     }
635 
636     static constexpr size_t minArgCount = 2;
637     size_t argCount = minArgCount;
638     napi_value args[minArgCount] = { nullptr, nullptr };
639     napi_value jsThis = nullptr;
640     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
641     if (status != napi_ok || jsThis == nullptr || argCount < minArgCount) {
642         MEDIA_LOGE("Failed to retrieve details about the callback");
643         return result;
644     }
645 
646     VideoRecorderNapi *recorderNapi = nullptr;
647     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
648     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, result, "Failed to retrieve instance");
649 
650     napi_valuetype valueType0 = napi_undefined;
651     napi_valuetype valueType1 = napi_undefined;
652     if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string ||
653         napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
654         recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
655         return result;
656     }
657 
658     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
659     MEDIA_LOGD("callbackName: %{public}s", callbackName.c_str());
660 
661     napi_ref ref = nullptr;
662     status = napi_create_reference(env, args[1], 1, &ref);
663     CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create reference!");
664 
665     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
666     recorderNapi->SetCallbackReference(callbackName, autoRef);
667     return result;
668 }
669 
670 
GetConfig(napi_env env,napi_value args,std::unique_ptr<VideoRecorderAsyncContext> & ctx,VideoRecorderProperties & properties)671 void VideoRecorderNapi::GetConfig(napi_env env, napi_value args,
672     std::unique_ptr<VideoRecorderAsyncContext> &ctx, VideoRecorderProperties &properties)
673 {
674     int32_t audioSource = AUDIO_SOURCE_INVALID;
675     int32_t videoSource = VIDEO_SOURCE_BUTT;
676 
677     bool ret = CommonNapi::GetPropertyInt32(env, args, "audioSourceType", audioSource);
678     if (ret) {
679         // audio + video
680         properties.audioSourceType = static_cast<AudioSourceType>(audioSource);
681     } else {
682         // pure video
683         ctx->napi->isPureVideo = true;
684         MEDIA_LOGI("No audioSource Type input!");
685     }
686 
687     (void)CommonNapi::GetPropertyInt32(env, args, "videoSourceType", videoSource);
688     properties.videoSourceType = static_cast<VideoSourceType>(videoSource);
689 
690     (void)CommonNapi::GetPropertyInt32(env, args, "rotation", properties.orientationHint);
691 
692     napi_value geoLocation = nullptr;
693     napi_get_named_property(env, args, "location", &geoLocation);
694     double tempLatitude = 0;
695     double tempLongitude = 0;
696     (void)CommonNapi::GetPropertyDouble(env, geoLocation, "latitude", tempLatitude);
697     (void)CommonNapi::GetPropertyDouble(env, geoLocation, "longitude", tempLongitude);
698     properties.location.latitude = static_cast<float>(tempLatitude);
699     properties.location.longitude = static_cast<float>(tempLongitude);
700 }
701 
GetVideoRecorderProperties(napi_env env,napi_value args,VideoRecorderProperties & properties)702 int32_t VideoRecorderNapi::GetVideoRecorderProperties(napi_env env, napi_value args,
703     VideoRecorderProperties &properties)
704 {
705     napi_value item = nullptr;
706     napi_get_named_property(env, args, "profile", &item);
707 
708     (void)CommonNapi::GetPropertyInt32(env, item, "audioBitrate", properties.profile.audioBitrate);
709     (void)CommonNapi::GetPropertyInt32(env, item, "audioChannels", properties.profile.audioChannels);
710     std::string audioCodec = CommonNapi::GetPropertyString(env, item, "audioCodec");
711     (void)MapMimeToAudioCodecFormat(audioCodec, properties.profile.audioCodecFormat);
712     (void)CommonNapi::GetPropertyInt32(env, item, "audioSampleRate", properties.profile.auidoSampleRate);
713     (void)CommonNapi::GetPropertyInt32(env, item, "durationTime", properties.profile.duration);
714     std::string outputFile = CommonNapi::GetPropertyString(env, item, "fileFormat");
715     (void)MapExtensionNameToOutputFormat(outputFile, properties.profile.outputFormat);
716     (void)CommonNapi::GetPropertyInt32(env, item, "videoBitrate", properties.profile.videoBitrate);
717     std::string videoCodec = CommonNapi::GetPropertyString(env, item, "videoCodec");
718     (void)MapMimeToVideoCodecFormat(videoCodec, properties.profile.videoCodecFormat);
719     (void)CommonNapi::GetPropertyInt32(env, item, "videoFrameWidth", properties.profile.videoFrameWidth);
720     (void)CommonNapi::GetPropertyInt32(env, item, "videoFrameHeight", properties.profile.videoFrameHeight);
721     (void)CommonNapi::GetPropertyInt32(env, item, "videoFrameRate", properties.profile.videoFrameRate);
722 
723     return MSERR_OK;
724 }
725 
SetVideoRecorderProperties(std::unique_ptr<VideoRecorderAsyncContext> & ctx,const VideoRecorderProperties & properties)726 int32_t VideoRecorderNapi::SetVideoRecorderProperties(std::unique_ptr<VideoRecorderAsyncContext> &ctx,
727     const VideoRecorderProperties &properties)
728 {
729     int32_t ret;
730     CHECK_AND_RETURN_RET(recorder_ != nullptr, MSERR_INVALID_OPERATION);
731     if (ctx->napi->isPureVideo != true) {
732         // audio + video
733         ret = recorder_->SetAudioSource(properties.audioSourceType, ctx->napi->audioSourceID);
734         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set AudioSource");
735 
736         ret = recorder_->SetVideoSource(properties.videoSourceType, ctx->napi->videoSourceID);
737         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set VideoSource");
738 
739         ret = recorder_->SetOutputFormat(properties.profile.outputFormat);
740         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set OutputFormat");
741 
742         ret = recorder_->SetAudioEncoder(ctx->napi->audioSourceID, properties.profile.audioCodecFormat);
743         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set audioCodec");
744 
745         ret = recorder_->SetAudioSampleRate(ctx->napi->audioSourceID, properties.profile.auidoSampleRate);
746         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set auidoSampleRate");
747 
748         ret = recorder_->SetAudioChannels(ctx->napi->audioSourceID, properties.profile.audioChannels);
749         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set audioChannels");
750 
751         ret = recorder_->SetAudioEncodingBitRate(ctx->napi->audioSourceID, properties.profile.audioBitrate);
752         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set audioBitrate");
753     } else {
754         ret = recorder_->SetVideoSource(properties.videoSourceType, ctx->napi->videoSourceID);
755         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set VideoSource");
756 
757         ret = recorder_->SetOutputFormat(properties.profile.outputFormat);
758         CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set OutputFormat");
759     }
760     ret = recorder_->SetVideoEncoder(ctx->napi->videoSourceID, properties.profile.videoCodecFormat);
761     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set videoCodec");
762 
763     ret = recorder_->SetVideoSize(ctx->napi->videoSourceID, properties.profile.videoFrameWidth,
764         properties.profile.videoFrameHeight);
765     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set videoSize");
766 
767     ret = recorder_->SetVideoFrameRate(ctx->napi->videoSourceID, properties.profile.videoFrameRate);
768     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set videoFrameRate");
769 
770     ret = recorder_->SetVideoEncodingBitRate(ctx->napi->videoSourceID, properties.profile.videoBitrate);
771     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to set videoBitrate");
772 
773     recorder_->SetLocation(properties.location.latitude, properties.location.longitude);
774     recorder_->SetOrientationHint(properties.orientationHint);
775 
776     return MSERR_OK;
777 }
778 
SetUrl(const std::string & urlPath)779 int32_t VideoRecorderNapi::SetUrl(const std::string &urlPath)
780 {
781     CHECK_AND_RETURN_RET_LOG(recorder_ != nullptr, MSERR_INVALID_OPERATION, "No memory");
782     const std::string fdHead = "fd://";
783 
784     if (urlPath.find(fdHead) != std::string::npos) {
785         int32_t fd = -1;
786         std::string inputFd = urlPath.substr(fdHead.size());
787         CHECK_AND_RETURN_RET(StrToInt(inputFd, fd) == true, MSERR_INVALID_VAL);
788         CHECK_AND_RETURN_RET(fd >= 0, MSERR_INVALID_OPERATION);
789         CHECK_AND_RETURN_RET(recorder_->SetOutputFile(fd) == MSERR_OK, MSERR_INVALID_OPERATION);
790     } else {
791         MEDIA_LOGE("invalid input uri, not a fd!");
792         return MSERR_INVALID_OPERATION;
793     }
794 
795     return MSERR_OK;
796 }
797 
IsSurfaceIdVaild(uint64_t surfaceID)798 bool VideoRecorderNapi::IsSurfaceIdVaild(uint64_t surfaceID)
799 {
800     auto surface = SurfaceUtils::GetInstance()->GetSurface(surfaceID);
801     if (surface == nullptr) {
802         return false;
803     }
804     return true;
805 }
806 
GetState(napi_env env,napi_callback_info info)807 napi_value VideoRecorderNapi::GetState(napi_env env, napi_callback_info info)
808 {
809     napi_value jsThis = nullptr;
810     napi_value result = nullptr;
811     napi_get_undefined(env, &result);
812 
813     auto asyncCtx = std::make_unique<VideoRecorderAsyncContext>(env);
814 
815     size_t argCount = 0;
816     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
817     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "Failed to retrieve details about the callback");
818 
819     VideoRecorderNapi *recorderNapi = nullptr;
820     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
821     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "Failed to retrieve instance");
822 
823     std::string curState = VideoRecorderState::STATE_ERROR;
824     if (recorderNapi->callbackNapi_ != nullptr) {
825         curState = recorderNapi->currentStates_;
826         MEDIA_LOGD("GetState success, State: %{public}s", curState.c_str());
827     }
828 
829     napi_value jsResult = nullptr;
830     status = napi_create_string_utf8(env, curState.c_str(), NAPI_AUTO_LENGTH, &jsResult);
831     CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_string_utf8 error");
832     return jsResult;
833 }
834 
835 // Synchronous interface can use this to report error
ErrorCallback(MediaServiceExtErrCode errCode)836 void VideoRecorderNapi::ErrorCallback(MediaServiceExtErrCode errCode)
837 {
838     if (callbackNapi_ != nullptr) {
839         auto napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
840         napiCb->SendErrorCallback(errCode);
841     }
842 }
843 
SetCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)844 void VideoRecorderNapi::SetCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
845 {
846     refMap_[callbackName] = ref;
847     if (callbackNapi_ != nullptr) {
848         auto napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
849         napiCb->SaveCallbackReference(callbackName, ref);
850     }
851 }
852 
CancelCallback()853 void VideoRecorderNapi::CancelCallback()
854 {
855     if (callbackNapi_ != nullptr) {
856         auto napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
857         napiCb->ClearCallbackReference();
858     }
859 }
860 } // namespace Media
861 } // namespace OHOS
862