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