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