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