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