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