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 "audio_recorder_napi.h"
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <climits>
20 #include "recorder_callback_napi.h"
21 #include "media_log.h"
22 #include "media_errors.h"
23 #include "media_permission.h"
24 #include "directory_ex.h"
25 #include "string_ex.h"
26 #include "common_napi.h"
27 #include "recorder_napi_utils.h"
28 #ifdef SUPPORT_JSSTACK
29 #include "xpower_event_js.h"
30 #endif
31 
32 namespace {
33 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_RECORDER, "AudioRecorderNapi"};
34 }
35 
36 namespace OHOS {
37 namespace Media {
38 thread_local napi_ref AudioRecorderNapi::constructor_ = nullptr;
39 const std::string CLASS_NAME = "AudioRecorder";
40 constexpr int32_t DEFAULT_AUDIO_ENCODER_BIT_RATE = 48000;
41 constexpr int32_t DEFAULT_AUDIO_SAMPLE_RATE = 48000;
42 constexpr int32_t DEFAULT_NUMBER_OF_CHANNELS = 2;
43 
AudioRecorderProperties()44 AudioRecorderNapi::AudioRecorderProperties::AudioRecorderProperties()
45     : sourceType(AUDIO_SOURCE_DEFAULT),
46       outputFormatType(FORMAT_DEFAULT),
47       audioCodecFormat(AUDIO_DEFAULT),
48       encodeBitRate(DEFAULT_AUDIO_ENCODER_BIT_RATE),
49       audioSampleRate(DEFAULT_AUDIO_SAMPLE_RATE),
50       numberOfChannels(DEFAULT_NUMBER_OF_CHANNELS)
51 {
52 }
53 
54 AudioRecorderNapi::AudioRecorderProperties::~AudioRecorderProperties() = default;
55 
AudioRecorderNapi()56 AudioRecorderNapi::AudioRecorderNapi()
57 {
58     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
59 }
60 
~AudioRecorderNapi()61 AudioRecorderNapi::~AudioRecorderNapi()
62 {
63     CancelCallback();
64     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy in ", FAKE_POINTER(this));
65     if (taskQue_ != nullptr) {
66         (void)taskQue_->Stop();
67     }
68     callbackNapi_ = nullptr;
69     recorderImpl_ = nullptr;
70 
71     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy out ", FAKE_POINTER(this));
72 }
73 
Init(napi_env env,napi_value exports)74 napi_value AudioRecorderNapi::Init(napi_env env, napi_value exports)
75 {
76     napi_property_descriptor properties[] = {
77         DECLARE_NAPI_FUNCTION("prepare", Prepare),
78         DECLARE_NAPI_FUNCTION("start", Start),
79         DECLARE_NAPI_FUNCTION("pause", Pause),
80         DECLARE_NAPI_FUNCTION("resume", Resume),
81         DECLARE_NAPI_FUNCTION("stop", Stop),
82         DECLARE_NAPI_FUNCTION("reset", Reset),
83         DECLARE_NAPI_FUNCTION("release", Release),
84         DECLARE_NAPI_FUNCTION("on", On)
85     };
86     napi_property_descriptor staticProperty[] = {
87         DECLARE_NAPI_STATIC_FUNCTION("createAudioRecorder", CreateAudioRecorder),
88     };
89 
90     napi_value constructor = nullptr;
91     napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
92         sizeof(properties) / sizeof(properties[0]), properties, &constructor);
93     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AudioRecorder class");
94 
95     status = napi_create_reference(env, constructor, 1, &constructor_);
96     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
97 
98     status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
99     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
100 
101     status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
102     CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
103 
104     MEDIA_LOGD("AudioRecorderNapi Init success");
105     return exports;
106 }
107 
Constructor(napi_env env,napi_callback_info info)108 napi_value AudioRecorderNapi::Constructor(napi_env env, napi_callback_info info)
109 {
110     napi_value result = nullptr;
111     napi_value jsThis = nullptr;
112     size_t argCount = 0;
113     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
114     if (status != napi_ok) {
115         napi_get_undefined(env, &result);
116         MEDIA_LOGE("Failed to retrieve details about the callback");
117         return result;
118     }
119 
120     AudioRecorderNapi *recorderNapi = new(std::nothrow) AudioRecorderNapi();
121     CHECK_AND_RETURN_RET_LOG(recorderNapi != nullptr, nullptr, "No memory");
122 
123     recorderNapi->env_ = env;
124     recorderNapi->recorderImpl_ = RecorderFactory::CreateRecorder();
125     if (recorderNapi->recorderImpl_ == nullptr) {
126         MEDIA_LOGE("failed to CreateRecorder");
127     }
128 
129     recorderNapi->taskQue_ = std::make_unique<TaskQueue>("RecorderNapi");
130     (void)recorderNapi->taskQue_->Start();
131 
132     if (recorderNapi->callbackNapi_ == nullptr && recorderNapi->recorderImpl_ != nullptr) {
133         recorderNapi->callbackNapi_ = std::make_shared<RecorderCallbackNapi>(env, false);
134         (void)recorderNapi->recorderImpl_->SetRecorderCallback(recorderNapi->callbackNapi_);
135     }
136 
137     status = napi_wrap(env, jsThis, reinterpret_cast<void *>(recorderNapi),
138         AudioRecorderNapi::Destructor, nullptr, nullptr);
139     if (status != napi_ok) {
140         napi_get_undefined(env, &result);
141         delete recorderNapi;
142         MEDIA_LOGE("Failed to wrap native instance");
143         return result;
144     }
145 
146     MEDIA_LOGD("Constructor success");
147     return jsThis;
148 }
149 
Destructor(napi_env env,void * nativeObject,void * finalize)150 void AudioRecorderNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
151 {
152     (void)env;
153     (void)finalize;
154     if (nativeObject != nullptr) {
155         delete reinterpret_cast<AudioRecorderNapi *>(nativeObject);
156     }
157     MEDIA_LOGD("Destructor success");
158 }
159 
CreateAudioRecorder(napi_env env,napi_callback_info info)160 napi_value AudioRecorderNapi::CreateAudioRecorder(napi_env env, napi_callback_info info)
161 {
162     napi_value result = nullptr;
163     napi_value constructor = nullptr;
164     napi_status status = napi_get_reference_value(env, constructor_, &constructor);
165     if (status != napi_ok) {
166         MEDIA_LOGE("Failed to get the representation of constructor object");
167         napi_get_undefined(env, &result);
168         return result;
169     }
170 
171     status = napi_new_instance(env, constructor, 0, nullptr, &result);
172     if (status != napi_ok) {
173         MEDIA_LOGE("new instance fail");
174         napi_get_undefined(env, &result);
175         return result;
176     }
177 
178     MEDIA_LOGD("CreateAudioRecorder success");
179     return result;
180 }
181 
CreateAudioRecorderAsync(napi_env env,napi_callback_info info)182 napi_value AudioRecorderNapi::CreateAudioRecorderAsync(napi_env env, napi_callback_info info)
183 {
184     napi_value result = nullptr;
185     napi_get_undefined(env, &result);
186     MEDIA_LOGD("CreateAudioRecorderAsync In");
187 
188     auto asyncCtx = std::make_unique<MediaAsyncContext>(env);
189 
190     // get args
191     napi_value jsThis = nullptr;
192     napi_value args[1] = { nullptr };
193     size_t argCount = 1;
194     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
195     if (status != napi_ok) {
196         asyncCtx->SignError(MSERR_EXT_INVALID_VAL, "failed to napi_get_cb_info");
197     }
198 
199     asyncCtx->callbackRef = CommonNapi::CreateReference(env, args[0]);
200     asyncCtx->deferred = CommonNapi::CreatePromise(env, asyncCtx->callbackRef, result);
201     asyncCtx->JsResult = std::make_unique<MediaJsResultInstance>(constructor_);
202     napi_value resource = nullptr;
203     napi_create_string_utf8(env, "CreateAudioRecorderAsync", NAPI_AUTO_LENGTH, &resource);
204     NAPI_CALL(env, napi_create_async_work(env, nullptr, resource, [](napi_env env, void* data) {},
205         MediaAsyncContext::CompleteCallback, static_cast<void *>(asyncCtx.get()), &asyncCtx->work));
206     NAPI_CALL(env, napi_queue_async_work(env, asyncCtx->work));
207     asyncCtx.release();
208     MEDIA_LOGD("CreateAudioRecorderAsync Out");
209 
210     return result;
211 }
212 
Prepare(napi_env env,napi_callback_info info)213 napi_value AudioRecorderNapi::Prepare(napi_env env, napi_callback_info info)
214 {
215     napi_value undefinedResult = nullptr;
216     napi_get_undefined(env, &undefinedResult);
217     napi_value jsThis = nullptr;
218     napi_value args[1] = {nullptr};
219 
220     size_t argCount = 1;
221     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
222     if (status != napi_ok || jsThis == nullptr || argCount < 1) {
223         MEDIA_LOGE("Failed to retrieve details about the callback");
224         return undefinedResult;
225     }
226 
227     auto asyncCtx = std::make_unique<MediaAsyncContext>(env);
228     if (!SystemPermission()) {
229         asyncCtx->SignError(MSERR_EXT_API9_PERMISSION_DENIED, "CreateVideoRecorder no system app");
230     }
231 
232     if (!MediaPermission::CheckMicPermission()) {
233         asyncCtx->SignError(MSERR_EXT_API9_NO_PERMISSION, "CreateVideoRecorder no MicPermission");
234     }
235 
236     AudioRecorderNapi *recorderNapi = nullptr;
237     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
238     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
239         "Failed to retrieve instance");
240 
241     napi_valuetype valueType = napi_undefined;
242     if (napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
243         recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
244         return undefinedResult;
245     }
246 
247     std::string uriPath = "invalid uri";
248     AudioRecorderProperties audioProperties;
249     if (recorderNapi->GetAudioUriPath(env, args[0], uriPath) != MSERR_OK) {
250         recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
251         return undefinedResult;
252     }
253 
254     if (recorderNapi->GetAudioProperties(env, args[0], audioProperties) != MSERR_OK) {
255         recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
256         return undefinedResult;
257     }
258 
259     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
260     auto task = std::make_shared<TaskHandler<void>>([recorderNapi, uriPath, audioProperties]() {
261         int32_t ret = recorderNapi->OnPrepare(uriPath, audioProperties);
262         if (ret == MSERR_OK) {
263             recorderNapi->StateCallback(PREPARE_CALLBACK_NAME);
264         } else {
265             recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
266         }
267         MEDIA_LOGD("Prepare success");
268     });
269     (void)recorderNapi->taskQue_->EnqueueTask(task);
270 
271     return undefinedResult;
272 }
273 
GetAudioEncAndFileFormat(napi_env env,napi_value args,AudioRecorderProperties & properties)274 bool AudioRecorderNapi::GetAudioEncAndFileFormat(napi_env env, napi_value args, AudioRecorderProperties &properties)
275 {
276     bool ret = false;
277     properties.outputFormatType = FORMAT_MPEG_4;
278     properties.audioCodecFormat = AAC_LC;
279 
280     napi_status status = napi_has_named_property(env, args, "fileFormat", &ret);
281     if (status == napi_ok && ret) {
282         std::string outputFile = CommonNapi::GetPropertyString(env, args, "fileFormat");
283         (void)MapExtensionNameToOutputFormat(outputFile, properties.outputFormatType);
284     } else {
285         status = napi_has_named_property(env, args, "format", &ret);
286         if (status == napi_ok && ret) {
287             int32_t fileFormat = 0;
288             (void)CommonNapi::GetPropertyInt32(env, args, "format", fileFormat);
289             switch (fileFormat) {
290                 case JS_DEFAULT_FILE_FORMAT:
291                 case JS_MPEG_4:
292                     properties.outputFormatType = FORMAT_MPEG_4;
293                     break;
294                 case JS_AAC_ADTS:
295                     properties.outputFormatType = FORMAT_M4A;
296                     break;
297                 default:
298                     return false;
299             }
300         }
301     }
302 
303     status = napi_has_named_property(env, args, "audioEncoderMime", &ret);
304     if (status == napi_ok && ret) {
305         std::string audioMime = CommonNapi::GetPropertyString(env, args, "audioEncoderMime");
306         (void)MapMimeToAudioCodecFormat(audioMime, properties.audioCodecFormat);
307     } else {
308         status = napi_has_named_property(env, args, "audioEncoder", &ret);
309         if (status == napi_ok && ret) {
310             int32_t audioEncoder = 0;
311             (void)CommonNapi::GetPropertyInt32(env, args, "audioEncoder", audioEncoder);
312             switch (audioEncoder) {
313                 case JS_AAC_LC:
314                     properties.audioCodecFormat = AAC_LC;
315                     break;
316                 case JS_DEFAULT_ENCORD_TYPE:
317                 default:
318                     return false;
319             }
320         }
321     }
322 
323     return true;
324 }
325 
GetAudioProperties(napi_env env,napi_value args,AudioRecorderProperties & properties)326 int32_t AudioRecorderNapi::GetAudioProperties(napi_env env, napi_value args, AudioRecorderProperties &properties)
327 {
328     properties.sourceType = AUDIO_MIC;
329 
330     bool ret = GetAudioEncAndFileFormat(env, args, properties);
331     CHECK_AND_RETURN_RET_LOG(ret == true, MSERR_INVALID_OPERATION, "invalid audio encode or format");
332 
333     napi_value geoLocation = nullptr;
334     napi_get_named_property(env, args, "location", &geoLocation);
335     double tempLatitude = 0;
336     double tempLongitude = 0;
337     (void)CommonNapi::GetPropertyDouble(env, geoLocation, "latitude", tempLatitude);
338     (void)CommonNapi::GetPropertyDouble(env, geoLocation, "longitude", tempLongitude);
339     properties.location.latitude = static_cast<float>(tempLatitude);
340     properties.location.longitude = static_cast<float>(tempLongitude);
341 
342     (void)CommonNapi::GetPropertyInt32(env, args, "audioEncodeBitRate", properties.encodeBitRate);
343     (void)CommonNapi::GetPropertyInt32(env, args, "audioSampleRate", properties.audioSampleRate);
344     (void)CommonNapi::GetPropertyInt32(env, args, "numberOfChannels", properties.numberOfChannels);
345     return MSERR_OK;
346 }
347 
GetAudioUriPath(napi_env env,napi_value args,std::string & uriPath)348 int32_t AudioRecorderNapi::GetAudioUriPath(napi_env env, napi_value args, std::string &uriPath)
349 {
350     bool exist = false;
351     napi_status status = napi_has_named_property(env, args, "uri", &exist);
352     CHECK_AND_RETURN_RET_LOG(status == napi_ok && exist, MSERR_INVALID_OPERATION, "can not find uri property");
353 
354     napi_value configItem = nullptr;
355     status = napi_get_named_property(env, args, "uri", &configItem);
356     CHECK_AND_RETURN_RET_LOG(status == napi_ok, MSERR_INVALID_OPERATION, "can not get uri property");
357 
358     char buffer[PATH_MAX] = {0};
359     size_t bytesToCopy = 0;
360     status = napi_get_value_string_latin1(env, configItem, buffer, PATH_MAX - 1, &bytesToCopy);
361     CHECK_AND_RETURN_RET_LOG(status == napi_ok, MSERR_INVALID_OPERATION, "can not get uri content");
362 
363     uriPath = buffer;
364     return MSERR_OK;
365 }
366 
OnPrepare(const std::string & uriPath,const AudioRecorderProperties & properties)367 int32_t AudioRecorderNapi::OnPrepare(const std::string &uriPath, const AudioRecorderProperties &properties)
368 {
369     CHECK_AND_RETURN_RET_LOG(recorderImpl_ != nullptr, MSERR_INVALID_OPERATION, "No memory");
370     int32_t sourceId = -1;
371     int32_t ret = recorderImpl_->SetAudioSource(properties.sourceType, sourceId);
372     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetAudioSource");
373 
374     ret = recorderImpl_->SetOutputFormat(properties.outputFormatType);
375     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetOutputFormat");
376 
377     ret = recorderImpl_->SetAudioEncoder(sourceId, properties.audioCodecFormat);
378     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetAudioEncoder");
379 
380     CHECK_AND_RETURN_RET_LOG(properties.encodeBitRate > 0, MSERR_INVALID_VAL, "encodeBitRate invalid value");
381     ret = recorderImpl_->SetAudioEncodingBitRate(sourceId, properties.encodeBitRate);
382     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetAudioEncodingBitRate");
383 
384     CHECK_AND_RETURN_RET_LOG(properties.audioSampleRate > 0, MSERR_INVALID_VAL, "audioSampleRate invalid value");
385     ret = recorderImpl_->SetAudioSampleRate(sourceId, properties.audioSampleRate);
386     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetAudioSampleRate");
387 
388     CHECK_AND_RETURN_RET_LOG(properties.numberOfChannels > 0, MSERR_INVALID_VAL, "numberOfChannels invalid value");
389     ret = recorderImpl_->SetAudioChannels(sourceId, properties.numberOfChannels);
390     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetAudioChannels");
391 
392     recorderImpl_->SetLocation(properties.location.latitude, properties.location.longitude);
393 
394     ret = SetUri(uriPath);
395     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to SetUri");
396 
397     ret = recorderImpl_->Prepare();
398     CHECK_AND_RETURN_RET_LOG(ret == MSERR_OK, MSERR_INVALID_OPERATION, "Fail to Prepare");
399     return MSERR_OK;
400 }
401 
Start(napi_env env,napi_callback_info info)402 napi_value AudioRecorderNapi::Start(napi_env env, napi_callback_info info)
403 {
404     napi_value undefinedResult = nullptr;
405     napi_get_undefined(env, &undefinedResult);
406 
407     size_t argCount = 0;
408     napi_value jsThis = nullptr;
409     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
410     if (status != napi_ok || jsThis == nullptr) {
411         MEDIA_LOGE("Failed to retrieve details about the callback");
412         return undefinedResult;
413     }
414 
415     AudioRecorderNapi *recorderNapi = nullptr;
416     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
417     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
418         "Failed to retrieve instance");
419 
420     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
421     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
422     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
423         int32_t ret = napi->recorderImpl_->Start();
424         if (ret == MSERR_OK) {
425             napi->StateCallback(START_CALLBACK_NAME);
426         } else {
427             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
428         }
429         MEDIA_LOGD("Start success");
430     });
431 #ifdef SUPPORT_JSSTACK
432     HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
433 #endif
434     (void)recorderNapi->taskQue_->EnqueueTask(task);
435 
436     return undefinedResult;
437 }
438 
Pause(napi_env env,napi_callback_info info)439 napi_value AudioRecorderNapi::Pause(napi_env env, napi_callback_info info)
440 {
441     napi_value undefinedResult = nullptr;
442     napi_get_undefined(env, &undefinedResult);
443 
444     size_t argCount = 0;
445     napi_value jsThis = nullptr;
446     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
447     if (status != napi_ok || jsThis == nullptr) {
448         MEDIA_LOGE("Failed to retrieve details about the callback");
449         return undefinedResult;
450     }
451 
452     AudioRecorderNapi *recorderNapi = nullptr;
453     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
454     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
455         "Failed to retrieve instance");
456 
457     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
458     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
459     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
460         int32_t ret = napi->recorderImpl_->Pause();
461         if (ret == MSERR_OK) {
462             napi->StateCallback(PAUSE_CALLBACK_NAME);
463         } else {
464             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
465         }
466         MEDIA_LOGD("Pause success");
467     });
468     (void)recorderNapi->taskQue_->EnqueueTask(task);
469     return undefinedResult;
470 }
471 
Resume(napi_env env,napi_callback_info info)472 napi_value AudioRecorderNapi::Resume(napi_env env, napi_callback_info info)
473 {
474     napi_value undefinedResult = nullptr;
475     napi_get_undefined(env, &undefinedResult);
476 
477     size_t argCount = 0;
478     napi_value jsThis = nullptr;
479     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
480     if (status != napi_ok || jsThis == nullptr) {
481         MEDIA_LOGE("Failed to retrieve details about the callback");
482         return undefinedResult;
483     }
484 
485     AudioRecorderNapi *recorderNapi = nullptr;
486     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
487     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
488         "Failed to retrieve instance");
489 
490     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
491     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
492     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
493         int32_t ret = napi->recorderImpl_->Resume();
494         if (ret == MSERR_OK) {
495             napi->StateCallback(RESUME_CALLBACK_NAME);
496         } else {
497             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
498         }
499         MEDIA_LOGD("Resume success");
500     });
501 #ifdef SUPPORT_JSSTACK
502     HiviewDFX::ReportXPowerJsStackSysEvent(env, "STREAM_CHANGE", "SRC=Media");
503 #endif
504     (void)recorderNapi->taskQue_->EnqueueTask(task);
505     return undefinedResult;
506 }
507 
Stop(napi_env env,napi_callback_info info)508 napi_value AudioRecorderNapi::Stop(napi_env env, napi_callback_info info)
509 {
510     napi_value undefinedResult = nullptr;
511     napi_get_undefined(env, &undefinedResult);
512 
513     size_t argCount = 0;
514     napi_value jsThis = nullptr;
515     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
516     if (status != napi_ok || jsThis == nullptr) {
517         MEDIA_LOGE("Failed to retrieve details about the callback");
518         return undefinedResult;
519     }
520 
521     AudioRecorderNapi *recorderNapi = nullptr;
522     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
523     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
524         "Failed to retrieve instance");
525 
526     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
527     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
528     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
529         int32_t ret = napi->recorderImpl_->Stop(false);
530         if (ret == MSERR_OK) {
531             napi->StateCallback(STOP_CALLBACK_NAME);
532         } else {
533             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
534         }
535         MEDIA_LOGD("Stop success");
536     });
537     (void)recorderNapi->taskQue_->EnqueueTask(task);
538     return undefinedResult;
539 }
540 
Reset(napi_env env,napi_callback_info info)541 napi_value AudioRecorderNapi::Reset(napi_env env, napi_callback_info info)
542 {
543     napi_value undefinedResult = nullptr;
544     napi_get_undefined(env, &undefinedResult);
545 
546     size_t argCount = 0;
547     napi_value jsThis = nullptr;
548     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
549     if (status != napi_ok || jsThis == nullptr) {
550         MEDIA_LOGE("Failed to retrieve details about the callback");
551         return undefinedResult;
552     }
553 
554     AudioRecorderNapi *recorderNapi = nullptr;
555     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
556     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
557         "Failed to retrieve instance");
558 
559     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
560     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
561     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
562         int32_t ret = napi->recorderImpl_->Reset();
563         if (ret == MSERR_OK) {
564             napi->StateCallback(RESET_CALLBACK_NAME);
565         } else {
566             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
567         }
568         MEDIA_LOGD("Reset success");
569     });
570     (void)recorderNapi->taskQue_->EnqueueTask(task);
571     return undefinedResult;
572 }
573 
Release(napi_env env,napi_callback_info info)574 napi_value AudioRecorderNapi::Release(napi_env env, napi_callback_info info)
575 {
576     napi_value undefinedResult = nullptr;
577     napi_get_undefined(env, &undefinedResult);
578 
579     size_t argCount = 0;
580     napi_value jsThis = nullptr;
581     napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
582     if (status != napi_ok || jsThis == nullptr) {
583         MEDIA_LOGE("Failed to retrieve details about the callback");
584         return undefinedResult;
585     }
586 
587     AudioRecorderNapi *recorderNapi = nullptr;
588     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
589     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
590         "Failed to retrieve instance");
591 
592     CHECK_AND_RETURN_RET_LOG(recorderNapi->recorderImpl_ != nullptr, undefinedResult, "No memory");
593     CHECK_AND_RETURN_RET_LOG(recorderNapi->taskQue_ != nullptr, undefinedResult, "No TaskQue");
594     auto task = std::make_shared<TaskHandler<void>>([napi = recorderNapi]() {
595         int32_t ret = napi->recorderImpl_->Release();
596         if (ret == MSERR_OK) {
597             napi->StateCallback(RELEASE_CALLBACK_NAME);
598         } else {
599             napi->ErrorCallback(MSERR_EXT_UNKNOWN);
600         }
601         napi->CancelCallback();
602         MEDIA_LOGD("Release success");
603     });
604     (void)recorderNapi->taskQue_->EnqueueTask(task);
605     return undefinedResult;
606 }
607 
On(napi_env env,napi_callback_info info)608 napi_value AudioRecorderNapi::On(napi_env env, napi_callback_info info)
609 {
610     napi_value undefinedResult = nullptr;
611     napi_get_undefined(env, &undefinedResult);
612 
613     static constexpr size_t minArgCount = 2;
614     size_t argCount = minArgCount;
615     napi_value args[minArgCount] = { nullptr, nullptr };
616     napi_value jsThis = nullptr;
617     napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
618     if (status != napi_ok || jsThis == nullptr || argCount < minArgCount) {
619         MEDIA_LOGE("Failed to retrieve details about the callback");
620         return undefinedResult;
621     }
622 
623     AudioRecorderNapi *recorderNapi = nullptr;
624     status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&recorderNapi));
625     CHECK_AND_RETURN_RET_LOG(status == napi_ok && recorderNapi != nullptr, undefinedResult,
626         "Failed to retrieve instance");
627 
628     napi_valuetype valueType0 = napi_undefined;
629     napi_valuetype valueType1 = napi_undefined;
630     if (napi_typeof(env, args[0], &valueType0) != napi_ok || valueType0 != napi_string ||
631         napi_typeof(env, args[1], &valueType1) != napi_ok || valueType1 != napi_function) {
632         recorderNapi->ErrorCallback(MSERR_EXT_INVALID_VAL);
633         return undefinedResult;
634     }
635 
636     std::string callbackName = CommonNapi::GetStringArgument(env, args[0]);
637     MEDIA_LOGD("callbackName: %{public}s", callbackName.c_str());
638 
639     napi_ref ref = nullptr;
640     status = napi_create_reference(env, args[1], 1, &ref);
641     CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, undefinedResult, "failed to create reference!");
642 
643     std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
644     recorderNapi->SetCallbackReference(callbackName, autoRef);
645     return undefinedResult;
646 }
647 
CheckValidPath(const std::string & filePath,std::string & realPath)648 int32_t AudioRecorderNapi::CheckValidPath(const std::string &filePath, std::string &realPath)
649 {
650     if (!PathToRealPath(filePath, realPath)) {
651         MEDIA_LOGE("Configured output filePath invalid, ignore !");
652         return MSERR_INVALID_VAL;
653     }
654     struct stat s;
655     if (stat(realPath.c_str(), &s) != 0) {
656         MEDIA_LOGE("Configured output filePath invalid, ignore !");
657         return MSERR_INVALID_VAL;
658     }
659     if ((s.st_mode & S_IFREG) == 0) {
660         MEDIA_LOGE("Configured output filePath invalid, ignore !");
661         return MSERR_INVALID_VAL;
662     }
663     return MSERR_OK;
664 }
665 
SetUri(const std::string & uriPath)666 int32_t AudioRecorderNapi::SetUri(const std::string &uriPath)
667 {
668     CHECK_AND_RETURN_RET_LOG(recorderImpl_ != nullptr, MSERR_INVALID_OPERATION, "No memory");
669     const std::string fdHead = "fd://";
670 
671     if (uriPath.find(fdHead) != std::string::npos) {
672         int32_t fd = -1;
673         std::string inputFd = uriPath.substr(fdHead.size());
674         CHECK_AND_RETURN_RET(StrToInt(inputFd, fd) == true, MSERR_INVALID_VAL);
675         CHECK_AND_RETURN_RET(fd >= 0, MSERR_INVALID_OPERATION);
676         CHECK_AND_RETURN_RET(recorderImpl_->SetOutputFile(fd) == MSERR_OK, MSERR_INVALID_OPERATION);
677     } else {
678         MEDIA_LOGE("invalid input uri, not a fd!");
679         return MSERR_INVALID_OPERATION;
680     }
681 
682     return MSERR_OK;
683 }
684 
ErrorCallback(MediaServiceExtErrCode errCode)685 void AudioRecorderNapi::ErrorCallback(MediaServiceExtErrCode errCode)
686 {
687     if (callbackNapi_ != nullptr) {
688         std::shared_ptr<RecorderCallbackNapi> napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
689         napiCb->SendErrorCallback(errCode);
690     }
691 }
692 
StateCallback(const std::string & callbackName)693 void AudioRecorderNapi::StateCallback(const std::string &callbackName)
694 {
695     if (callbackNapi_ != nullptr) {
696         std::shared_ptr<RecorderCallbackNapi> napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
697         napiCb->SendStateCallback(callbackName);
698     }
699 }
700 
SetCallbackReference(const std::string & callbackName,std::shared_ptr<AutoRef> ref)701 void AudioRecorderNapi::SetCallbackReference(const std::string &callbackName, std::shared_ptr<AutoRef> ref)
702 {
703     refMap_[callbackName] = ref;
704     if (callbackNapi_ != nullptr) {
705         std::shared_ptr<RecorderCallbackNapi> napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
706         napiCb->SaveCallbackReference(callbackName, ref);
707     }
708 }
709 
CancelCallback()710 void AudioRecorderNapi::CancelCallback()
711 {
712     if (callbackNapi_ != nullptr) {
713         std::shared_ptr<RecorderCallbackNapi> napiCb = std::static_pointer_cast<RecorderCallbackNapi>(callbackNapi_);
714         napiCb->ClearCallbackReference();
715     }
716 }
717 } // namespace Media
718 } // namespace OHOS
719