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