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