1 /*
2 * Copyright (c) 2025 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 #ifndef LOG_TAG
16 #define LOG_TAG "NapiAudioLoopback"
17 #endif
18
19 #include "napi_audio_loopback.h"
20
21 #include "napi_param_utils.h"
22 #include "napi_audio_error.h"
23 #include "napi_audio_enum.h"
24 #include "napi_audio_loopback_callback.h"
25 #include "audio_stream_manager.h"
26 #include "audio_manager_log.h"
27
28 using namespace std;
29
30 namespace OHOS {
31 namespace AudioStandard {
32 static __thread napi_ref g_loopbackConstructor = nullptr;
33 static constexpr double MIN_VOLUME_IN_DOUBLE = 0.0;
34 static constexpr double MAX_VOLUME_IN_DOUBLE = 1.0;
35 mutex NapiAudioLoopback::createMutex_;
36 int32_t NapiAudioLoopback::isConstructSuccess_ = SUCCESS;
37 AudioLoopbackMode NapiAudioLoopback::sLoopbackMode_ = LOOPBACK_HARDWARE;
38
NapiAudioLoopback()39 NapiAudioLoopback::NapiAudioLoopback()
40 : loopback_(nullptr), env_(nullptr) {}
41
42 NapiAudioLoopback::~NapiAudioLoopback() = default;
43
Destructor(napi_env env,void * nativeObject,void * finalizeHint)44 void NapiAudioLoopback::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
45 {
46 if (nativeObject == nullptr) {
47 AUDIO_WARNING_LOG("Native object is null");
48 return;
49 }
50 auto obj = static_cast<NapiAudioLoopback *>(nativeObject);
51 ObjectRefMap<NapiAudioLoopback>::DecreaseRef(obj);
52 AUDIO_INFO_LOG("Decrease obj count");
53 }
54
Init(napi_env env,napi_value exports)55 napi_value NapiAudioLoopback::Init(napi_env env, napi_value exports)
56 {
57 napi_status status;
58 napi_value constructor;
59 napi_value result = nullptr;
60 const int32_t refCount = 1;
61 napi_get_undefined(env, &result);
62 AUDIO_DEBUG_LOG("NapiAudioLoopback::Init");
63 napi_property_descriptor audio_loopback_properties[] = {
64 DECLARE_NAPI_FUNCTION("getStatus", GetStatus),
65 DECLARE_NAPI_FUNCTION("setVolume", SetVolume),
66 DECLARE_NAPI_FUNCTION("enable", Enable),
67 DECLARE_NAPI_FUNCTION("on", On),
68 DECLARE_NAPI_FUNCTION("off", Off),
69 DECLARE_NAPI_FUNCTION("setReverbPreset", SetReverbPreset),
70 DECLARE_NAPI_FUNCTION("getReverbPreset", GetReverbPreset),
71 DECLARE_NAPI_FUNCTION("setEqualizerPreset", SetEqualizerPreset),
72 DECLARE_NAPI_FUNCTION("getEqualizerPreset", GetEqualizerPreset),
73 };
74
75 napi_property_descriptor static_prop[] = {
76 DECLARE_NAPI_STATIC_FUNCTION("createAudioLoopback", CreateAudioLoopback),
77 };
78
79 status = napi_define_class(env, NAPI_AUDIO_LOOPBACK_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Construct, nullptr,
80 sizeof(audio_loopback_properties) / sizeof(audio_loopback_properties[PARAM0]),
81 audio_loopback_properties, &constructor);
82 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_class failed");
83
84 status = napi_create_reference(env, constructor, refCount, &g_loopbackConstructor);
85 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_reference failed");
86
87 status = napi_set_named_property(env, exports, NAPI_AUDIO_LOOPBACK_CLASS_NAME.c_str(), constructor);
88 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_set_named_property failed");
89
90 status = napi_define_properties(env, exports,
91 sizeof(static_prop) / sizeof(static_prop[PARAM0]), static_prop);
92 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_define_properties failed");
93
94 return exports;
95 }
96
Construct(napi_env env,napi_callback_info info)97 napi_value NapiAudioLoopback::Construct(napi_env env, napi_callback_info info)
98 {
99 napi_status status;
100 napi_value result = nullptr;
101 napi_get_undefined(env, &result);
102
103 size_t argCount = ARGS_TWO;
104 napi_value thisVar = nullptr;
105 status = napi_get_cb_info(env, info, &argCount, nullptr, &thisVar, nullptr);
106 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
107
108 unique_ptr<NapiAudioLoopback> napiLoopback = make_unique<NapiAudioLoopback>();
109 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr, result, "No memory");
110 ObjectRefMap<NapiAudioLoopback>::Insert(napiLoopback.get());
111
112 napiLoopback->env_ = env;
113 auto loopbackMode = sLoopbackMode_;
114 auto streamManager = AudioStreamManager::GetInstance();
115 if (streamManager != nullptr && streamManager->IsAudioLoopbackSupported(loopbackMode)) {
116 napiLoopback->loopback_ = AudioLoopback::CreateAudioLoopback(loopbackMode);
117 if (napiLoopback->loopback_ == nullptr) {
118 AUDIO_ERR_LOG("AudioLoopback Create failed");
119 NapiAudioLoopback::isConstructSuccess_ = NAPI_ERR_NO_PERMISSION;
120 }
121 } else {
122 AUDIO_ERR_LOG("AudioLoopback not supported");
123 NapiAudioLoopback::isConstructSuccess_ = NAPI_ERR_UNSUPPORTED;
124 }
125
126 if (napiLoopback->loopback_ != nullptr && napiLoopback->callbackNapi_ == nullptr) {
127 napiLoopback->callbackNapi_ = std::make_shared<NapiAudioLoopbackCallback>(env);
128 CHECK_AND_RETURN_RET_LOG(napiLoopback->callbackNapi_ != nullptr, nullptr, "No memory");
129 int32_t ret = napiLoopback->loopback_->SetAudioLoopbackCallback(napiLoopback->callbackNapi_);
130 CHECK_AND_RETURN_RET_LOG(!ret, result, "Construct SetLoopbackCallback failed");
131 }
132
133 status = napi_wrap(env, thisVar, static_cast<void*>(napiLoopback.get()),
134 NapiAudioLoopback::Destructor, nullptr, nullptr);
135 if (status != napi_ok) {
136 ObjectRefMap<NapiAudioLoopback>::Erase(napiLoopback.get());
137 return result;
138 }
139 napiLoopback.release();
140 return thisVar;
141 }
142
CreateAudioLoopbackWrapper(napi_env env,AudioLoopbackMode loopbackMode)143 napi_value NapiAudioLoopback::CreateAudioLoopbackWrapper(napi_env env, AudioLoopbackMode loopbackMode)
144 {
145 lock_guard<mutex> lock(createMutex_);
146 napi_status status = napi_invalid_arg;
147 napi_value result = nullptr;
148 napi_value constructor;
149
150 status = napi_get_reference_value(env, g_loopbackConstructor, &constructor);
151 if (status == napi_ok) {
152 sLoopbackMode_ = loopbackMode;
153 status = napi_new_instance(env, constructor, 0, nullptr, &result);
154 }
155 if (status != napi_ok) {
156 AUDIO_ERR_LOG("Failed in CreateAudioLoopbackWrapper, %{public}d", status);
157 napi_get_undefined(env, &result);
158 }
159 return result;
160 }
161
CreateAudioLoopback(napi_env env,napi_callback_info info)162 napi_value NapiAudioLoopback::CreateAudioLoopback(napi_env env, napi_callback_info info)
163 {
164 AUDIO_INFO_LOG("CreateAudioLoopback");
165 auto context = std::make_shared<AudioLoopbackAsyncContext>();
166 if (context == nullptr) {
167 AUDIO_ERR_LOG("CreateAudioLoopback failed : no memory");
168 NapiAudioError::ThrowError(env, "CreateAudioLoopback failed : no memory", NAPI_ERR_NO_MEMORY);
169 return NapiParamUtils::GetUndefinedValue(env);
170 }
171
172 auto inputParser = [env, context](size_t argc, napi_value *argv) {
173 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
174 NAPI_ERR_INVALID_PARAM);
175 context->status = NapiParamUtils::GetValueInt32(env, context->loopbackMode, argv[PARAM0]);
176 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "GetAudioLoopbackMode failed",
177 NAPI_ERR_INVALID_PARAM);
178 NAPI_CHECK_ARGS_RETURN_VOID(context,
179 NapiAudioEnum::IsLegalInputArgumentAudioLoopbackMode(context->loopbackMode), "loopback mode invaild",
180 NAPI_ERR_INVALID_PARAM);
181 };
182 context->GetCbInfo(env, info, inputParser);
183
184 auto complete = [env, context](napi_value &output) {
185 AudioLoopbackMode loopbackMode = static_cast<AudioLoopbackMode>(context->loopbackMode);
186 output = CreateAudioLoopbackWrapper(env, loopbackMode);
187 // IsConstructSuccess_ Used when creating a loopback fails.
188 if (isConstructSuccess_ != SUCCESS) {
189 context->SignError(isConstructSuccess_);
190 isConstructSuccess_ = SUCCESS;
191 }
192 };
193
194 return NapiAsyncWork::Enqueue(env, context, "CreateAudioLoopback", nullptr, complete);
195 }
196
GetStatus(napi_env env,napi_callback_info info)197 napi_value NapiAudioLoopback::GetStatus(napi_env env, napi_callback_info info)
198 {
199 auto context = std::make_shared<AudioLoopbackAsyncContext>();
200 if (context == nullptr) {
201 AUDIO_ERR_LOG("GetStatus failed : no memory");
202 NapiAudioError::ThrowError(env, "GetStatus failed : no memory", NAPI_ERR_NO_MEMORY);
203 return NapiParamUtils::GetUndefinedValue(env);
204 }
205
206 context->GetCbInfo(env, info);
207
208 auto executor = [context]() {
209 CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
210 auto obj = reinterpret_cast<NapiAudioLoopback*>(context->native);
211 ObjectRefMap objectGuard(obj);
212 auto *napiAudioLoopback = objectGuard.GetPtr();
213 CHECK_AND_RETURN_LOG(CheckAudioLoopbackStatus(napiAudioLoopback, context),
214 "context object state is error.");
215 context->loopbackStatus = napiAudioLoopback->loopback_->GetStatus();
216 };
217
218 auto complete = [env, context](napi_value &output) {
219 NapiParamUtils::SetValueInt32(env, static_cast<int32_t>(context->loopbackStatus), output);
220 };
221 return NapiAsyncWork::Enqueue(env, context, "GetStatus", executor, complete);
222 }
223
SetVolume(napi_env env,napi_callback_info info)224 napi_value NapiAudioLoopback::SetVolume(napi_env env, napi_callback_info info)
225 {
226 auto context = std::make_shared<AudioLoopbackAsyncContext>();
227 if (context == nullptr) {
228 AUDIO_ERR_LOG("SetVolume failed : no memory");
229 NapiAudioError::ThrowError(env, "SetVolume failed : no memory", NAPI_ERR_NO_MEMORY);
230 return NapiParamUtils::GetUndefinedValue(env);
231 }
232
233 auto inputParser = [env, context](size_t argc, napi_value *argv) {
234 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
235 NAPI_ERR_INVALID_PARAM);
236 context->status = NapiParamUtils::GetValueDouble(env, context->volLevel, argv[PARAM0]);
237 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "set volume failed",
238 NAPI_ERR_INVALID_PARAM);
239 };
240
241 context->GetCbInfo(env, info, inputParser);
242
243 auto executor = [context]() {
244 CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
245 auto obj = reinterpret_cast<NapiAudioLoopback*>(context->native);
246 ObjectRefMap objectGuard(obj);
247 auto *napiAudioLoopback = objectGuard.GetPtr();
248 CHECK_AND_RETURN_LOG(CheckAudioLoopbackStatus(napiAudioLoopback, context),
249 "context object state is error.");
250 if (context->volLevel < MIN_VOLUME_IN_DOUBLE || context->volLevel > MAX_VOLUME_IN_DOUBLE) {
251 context->SignError(NAPI_ERR_INVALID_PARAM);
252 return;
253 }
254 context->intValue = napiAudioLoopback->loopback_->SetVolume(static_cast<float>(context->volLevel));
255 if (context->intValue != SUCCESS) {
256 context->SignError(NAPI_ERR_SYSTEM);
257 }
258 };
259
260 auto complete = [env](napi_value &output) {
261 output = NapiParamUtils::GetUndefinedValue(env);
262 };
263 return NapiAsyncWork::Enqueue(env, context, "SetVolume", executor, complete);
264 }
265
Enable(napi_env env,napi_callback_info info)266 napi_value NapiAudioLoopback::Enable(napi_env env, napi_callback_info info)
267 {
268 auto context = std::make_shared<AudioLoopbackAsyncContext>();
269 if (context == nullptr) {
270 AUDIO_ERR_LOG("Enable failed : no memory");
271 NapiAudioError::ThrowError(env, "Enable failed : no memory", NAPI_ERR_NO_MEMORY);
272 return NapiParamUtils::GetUndefinedValue(env);
273 }
274
275 auto inputParser = [env, context](size_t argc, napi_value *argv) {
276 NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments",
277 NAPI_ERR_INVALID_PARAM);
278 context->status = NapiParamUtils::GetValueBoolean(env, context->enable, argv[PARAM0]);
279 NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "enable parameter failed",
280 NAPI_ERR_INVALID_PARAM);
281 };
282
283 context->GetCbInfo(env, info, inputParser);
284
285 auto executor = [context]() {
286 CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
287 auto obj = reinterpret_cast<NapiAudioLoopback*>(context->native);
288 ObjectRefMap objectGuard(obj);
289 auto *napiAudioLoopback = objectGuard.GetPtr();
290 CHECK_AND_RETURN_LOG(CheckAudioLoopbackStatus(napiAudioLoopback, context),
291 "context object state is error.");
292 context->isTrue = napiAudioLoopback->loopback_->Enable(context->enable);
293 };
294
295 auto complete = [env, context](napi_value &output) {
296 NapiParamUtils::SetValueBoolean(env, context->isTrue, output);
297 };
298 return NapiAsyncWork::Enqueue(env, context, "Enable", executor, complete);
299 }
300
On(napi_env env,napi_callback_info info)301 napi_value NapiAudioLoopback::On(napi_env env, napi_callback_info info)
302 {
303 const size_t requireArgc = ARGS_TWO;
304 size_t argc = ARGS_THREE;
305
306 napi_value argv[requireArgc + 1] = {nullptr, nullptr, nullptr};
307 napi_value jsThis = nullptr;
308 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
309 CHECK_AND_RETURN_RET_LOG(status == napi_ok,
310 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM), "status error");
311 CHECK_AND_RETURN_RET_LOG(argc >= requireArgc, NapiAudioError::ThrowErrorAndReturn(env,
312 NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified"), "requireArgc is invaild");
313
314 napi_valuetype eventType = napi_undefined;
315 napi_typeof(env, argv[PARAM0], &eventType);
316 CHECK_AND_RETURN_RET_LOG(eventType == napi_string, NapiAudioError::ThrowErrorAndReturn(env,
317 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of eventType must be string"),
318 "eventType is invaild");
319
320 std::string callbackName = NapiParamUtils::GetStringArgument(env, argv[PARAM0]);
321 AUDIO_DEBUG_LOG("AudioLoopbackNapi: On callbackName: %{public}s", callbackName.c_str());
322
323 napi_valuetype handler = napi_undefined;
324 if (argc == requireArgc) {
325 napi_typeof(env, argv[PARAM1], &handler);
326 CHECK_AND_RETURN_RET_LOG(handler == napi_function, NapiAudioError::ThrowErrorAndReturn(env,
327 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of callback must be function"),
328 "handler is invaild");
329 } else {
330 napi_valuetype paramArg1 = napi_undefined;
331 napi_typeof(env, argv[PARAM1], ¶mArg1);
332 napi_valuetype expectedValType = napi_number; // Default. Reset it with 'callbackName' if check, if required.
333 CHECK_AND_RETURN_RET_LOG(paramArg1 == expectedValType, NapiAudioError::ThrowErrorAndReturn(env,
334 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of frame must be number"),
335 "paramArg1 is invaild");
336 const int32_t arg2 = ARGS_TWO;
337 napi_typeof(env, argv[arg2], &handler);
338 CHECK_AND_RETURN_RET_LOG(handler == napi_function, NapiAudioError::ThrowErrorAndReturn(env,
339 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of callback must be function"),
340 "handler2 is invaild");
341 }
342
343 return RegisterCallback(env, jsThis, argv, callbackName);
344 }
345
RegisterCallback(napi_env env,napi_value jsThis,napi_value * argv,const std::string & cbName)346 napi_value NapiAudioLoopback::RegisterCallback(napi_env env, napi_value jsThis,
347 napi_value *argv, const std::string &cbName)
348 {
349 NapiAudioLoopback *napiLoopback = nullptr;
350 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiLoopback));
351 CHECK_AND_RETURN_RET_LOG(status == napi_ok,
352 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM), "status error");
353 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
354 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
355 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
356 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
357
358 napi_value result = nullptr;
359 napi_get_undefined(env, &result);
360
361 if (!cbName.compare(STATUS_CHANGE_CALLBACK_NAME)) {
362 result = RegisterLoopbackCallback(env, argv, cbName, napiLoopback);
363 } else {
364 bool unknownCallback = true;
365 CHECK_AND_RETURN_RET_LOG(!unknownCallback, NapiAudioError::ThrowErrorAndReturn(env,
366 NAPI_ERROR_INVALID_PARAM,
367 "parameter verification failed: The param of type is not supported"), "loopback_ is nullptr");
368 }
369
370 return result;
371 }
372
RegisterLoopbackCallback(napi_env env,napi_value * argv,const std::string & cbName,NapiAudioLoopback * napiLoopback)373 napi_value NapiAudioLoopback::RegisterLoopbackCallback(napi_env env, napi_value *argv,
374 const std::string &cbName, NapiAudioLoopback *napiLoopback)
375 {
376 CHECK_AND_RETURN_RET_LOG(napiLoopback->callbackNapi_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
377 NAPI_ERR_NO_MEMORY), "callbackNapi_ is nullptr");
378
379 std::shared_ptr<NapiAudioLoopbackCallback> cb =
380 std::static_pointer_cast<NapiAudioLoopbackCallback>(napiLoopback->callbackNapi_);
381 cb->SaveCallbackReference(cbName, argv[PARAM1]);
382 if (cbName == STATUS_CHANGE_CALLBACK_NAME) {
383 if (!cb->GetArStatusChangeTsfnFlag()) {
384 cb->CreateArStatusChange(env);
385 }
386 }
387
388 napi_value result = nullptr;
389 napi_get_undefined(env, &result);
390 return result;
391 }
392
Off(napi_env env,napi_callback_info info)393 napi_value NapiAudioLoopback::Off(napi_env env, napi_callback_info info)
394 {
395 const size_t requireArgc = ARGS_TWO;
396 size_t argc = ARGS_THREE;
397
398 napi_value argv[requireArgc + 1] = {nullptr, nullptr, nullptr};
399 napi_value jsThis = nullptr;
400 napi_status status = napi_get_cb_info(env, info, &argc, argv, &jsThis, nullptr);
401 CHECK_AND_RETURN_RET_LOG(status == napi_ok,
402 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM), "status error");
403 CHECK_AND_RETURN_RET_LOG(argc <= requireArgc, NapiAudioError::ThrowErrorAndReturn(env,
404 NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified"), "argc is invaild");
405
406 napi_valuetype eventType = napi_undefined;
407 napi_typeof(env, argv[PARAM0], &eventType);
408 CHECK_AND_RETURN_RET_LOG(eventType == napi_string, NapiAudioError::ThrowErrorAndReturn(env,
409 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of eventType must be string"),
410 "eventType is invaild");
411
412 std::string callbackName = NapiParamUtils::GetStringArgument(env, argv[PARAM0]);
413 AUDIO_DEBUG_LOG("AudioLoopbackNapi: Off callbackName: %{public}s", callbackName.c_str());
414
415 return UnregisterCallback(env, jsThis, argc, argv, callbackName);
416 }
417
UnregisterCallback(napi_env env,napi_value jsThis,size_t argc,napi_value * argv,const std::string & cbName)418 napi_value NapiAudioLoopback::UnregisterCallback(napi_env env, napi_value jsThis, size_t argc, napi_value *argv,
419 const std::string &cbName)
420 {
421 NapiAudioLoopback *napiLoopback = nullptr;
422 napi_status status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiLoopback));
423 CHECK_AND_RETURN_RET_LOG(status == napi_ok,
424 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_SYSTEM), "status error");
425 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
426 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
427 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
428 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
429
430 if (!cbName.compare(STATUS_CHANGE_CALLBACK_NAME)) {
431 UnregisterLoopbackCallback(env, argc, cbName, argv, napiLoopback);
432 } else {
433 bool unknownCallback = true;
434 CHECK_AND_RETURN_RET_LOG(!unknownCallback, NapiAudioError::ThrowErrorAndReturn(env,
435 NAPI_ERR_INVALID_PARAM,
436 "parameter verification failed: The param of type is not supported"), "cbName is invaild");
437 }
438
439 napi_value result = nullptr;
440 napi_get_undefined(env, &result);
441 return result;
442 }
443
444 template <typename T>
UnregisterAudioLoopbackSingletonCallbackTemplate(napi_env env,napi_value callback,const std::string & cbName,std::shared_ptr<T> cb,std::function<int32_t (std::shared_ptr<T> callbackPtr,napi_value callback)> removeFunction=nullptr)445 static void UnregisterAudioLoopbackSingletonCallbackTemplate(napi_env env, napi_value callback,
446 const std::string &cbName, std::shared_ptr<T> cb,
447 std::function<int32_t(std::shared_ptr<T> callbackPtr, napi_value callback)> removeFunction = nullptr)
448 {
449 if (callback != nullptr) {
450 CHECK_AND_RETURN_LOG(cb->ContainSameJsCallbackInner(cbName, callback), "callback not exists!");
451 }
452 cb->RemoveCallbackReference(cbName, env, callback);
453
454 if (removeFunction == nullptr) {
455 return;
456 }
457 int32_t ret = removeFunction(cb, callback);
458 CHECK_AND_RETURN_LOG(ret == SUCCESS, "Unset of Loopback info change call failed");
459 return;
460 }
461
UnregisterLoopbackCallback(napi_env env,size_t argc,const std::string & cbName,napi_value * argv,NapiAudioLoopback * napiLoopback)462 void NapiAudioLoopback::UnregisterLoopbackCallback(napi_env env, size_t argc,
463 const std::string &cbName, napi_value *argv, NapiAudioLoopback *napiLoopback)
464 {
465 CHECK_AND_RETURN_LOG(napiLoopback->callbackNapi_ != nullptr, "napiLoopbackCallback is nullptr");
466
467 std::shared_ptr<NapiAudioLoopbackCallback> cb =
468 std::static_pointer_cast<NapiAudioLoopbackCallback>(napiLoopback->callbackNapi_);
469 auto callback = GetCallback(argc, argv);
470 UnregisterAudioLoopbackSingletonCallbackTemplate(env, callback, cbName, cb);
471 AUDIO_DEBUG_LOG("UnregisterLoopbackCallback is successful");
472 }
473
GetCallback(size_t argc,napi_value * argv)474 napi_value NapiAudioLoopback::GetCallback(size_t argc, napi_value *argv)
475 {
476 napi_value callback = nullptr;
477
478 if (argc == ARGS_TWO) {
479 callback = argv[PARAM1];
480 }
481 return callback;
482 }
483
CheckContextStatus(std::shared_ptr<AudioLoopbackAsyncContext> context)484 bool NapiAudioLoopback::CheckContextStatus(std::shared_ptr<AudioLoopbackAsyncContext> context)
485 {
486 CHECK_AND_RETURN_RET_LOG(context != nullptr, false, "context object is nullptr.");
487 if (context->native == nullptr) {
488 context->SignError(NAPI_ERR_SYSTEM);
489 return false;
490 }
491 return true;
492 }
493
CheckAudioLoopbackStatus(NapiAudioLoopback * napi,std::shared_ptr<AudioLoopbackAsyncContext> context)494 bool NapiAudioLoopback::CheckAudioLoopbackStatus(NapiAudioLoopback *napi,
495 std::shared_ptr<AudioLoopbackAsyncContext> context)
496 {
497 CHECK_AND_RETURN_RET_LOG(napi != nullptr, false, "napi object is nullptr.");
498 if (napi->loopback_ == nullptr) {
499 context->SignError(NAPI_ERR_SYSTEM);
500 return false;
501 }
502 return true;
503 }
504
GetParamWithSync(const napi_env & env,napi_callback_info info,size_t & argc,napi_value * args)505 NapiAudioLoopback* NapiAudioLoopback::GetParamWithSync(const napi_env &env, napi_callback_info info,
506 size_t &argc, napi_value *args)
507 {
508 NapiAudioLoopback *napiLoopback = nullptr;
509 napi_value jsThis = nullptr;
510 napi_status status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
511 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "status error");
512 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&napiLoopback));
513 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "napi_unwrap failed");
514 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr, nullptr, "napiLoopback is nullptr");
515 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, nullptr, "loopback_ is nullptr");
516 return napiLoopback;
517 }
518
SetReverbPreset(napi_env env,napi_callback_info info)519 napi_value NapiAudioLoopback::SetReverbPreset(napi_env env, napi_callback_info info)
520 {
521 napi_value result = nullptr;
522 size_t argc = ARGS_ONE;
523 napi_value argv[ARGS_ONE] = {};
524 NapiAudioLoopback *napiLoopback = GetParamWithSync(env, info, argc, argv);
525 CHECK_AND_RETURN_RET_LOG(argc >= ARGS_ONE, NapiAudioError::ThrowErrorAndReturn(env,
526 NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified"), "argcCount invalid");
527 napi_valuetype valueType = napi_undefined;
528 napi_typeof(env, argv[PARAM0], &valueType);
529 CHECK_AND_RETURN_RET_LOG(valueType == napi_number, NapiAudioError::ThrowErrorAndReturn(env,
530 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of mode must be number"),
531 "valueType invaild");
532 int32_t preset;
533 NapiParamUtils::GetValueInt32(env, preset, argv[PARAM0]);
534
535 if (!NapiAudioEnum::IsLegalInputArgumentAudioLoopbackReverbPreset(preset)) {
536 NapiAudioError::ThrowError(env, NAPI_ERR_INVALID_PARAM,
537 "parameter verification failed: The param of mode must be enum AudioLoopbackReverbPreset");
538 return result;
539 }
540 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
541 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
542 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
543 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
544 bool ret = napiLoopback->loopback_->SetReverbPreset(static_cast<AudioLoopbackReverbPreset>(preset));
545 napi_get_boolean(env, ret, &result);
546 return result;
547 }
548
GetReverbPreset(napi_env env,napi_callback_info info)549 napi_value NapiAudioLoopback::GetReverbPreset(napi_env env, napi_callback_info info)
550 {
551 size_t argc = PARAM0;
552 NapiAudioLoopback *napiLoopback = GetParamWithSync(env, info, argc, nullptr);
553 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
554 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
555 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
556 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
557 int32_t reverbPreset = static_cast<int32_t>(napiLoopback->loopback_->GetReverbPreset());
558 napi_value result = nullptr;
559 napi_status status = NapiParamUtils::SetValueInt32(env, reverbPreset, result);
560 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "SetValueInt32 failed");
561 return result;
562 }
563
SetEqualizerPreset(napi_env env,napi_callback_info info)564 napi_value NapiAudioLoopback::SetEqualizerPreset(napi_env env, napi_callback_info info)
565 {
566 napi_value result = nullptr;
567 size_t argc = ARGS_ONE;
568 napi_value argv[ARGS_ONE] = {};
569 NapiAudioLoopback *napiLoopback = GetParamWithSync(env, info, argc, argv);
570 CHECK_AND_RETURN_RET_LOG(argc >= ARGS_ONE, NapiAudioError::ThrowErrorAndReturn(env,
571 NAPI_ERR_INPUT_INVALID, "mandatory parameters are left unspecified"), "argcCount invalid");
572
573 napi_valuetype valueType = napi_undefined;
574 napi_typeof(env, argv[PARAM0], &valueType);
575 CHECK_AND_RETURN_RET_LOG(valueType == napi_number, NapiAudioError::ThrowErrorAndReturn(env,
576 NAPI_ERR_INPUT_INVALID, "incorrect parameter types: The type of mode must be number"),
577 "valueType invaild");
578 int32_t preset;
579 NapiParamUtils::GetValueInt32(env, preset, argv[PARAM0]);
580
581 if (!NapiAudioEnum::IsLegalInputArgumentAudioLoopbackEqualizerPreset(preset)) {
582 NapiAudioError::ThrowError(env, NAPI_ERR_INVALID_PARAM,
583 "parameter verification failed: The param of mode must be enum AudioLoopbackEqualizerPreset");
584 return result;
585 }
586 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
587 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
588 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
589 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
590 bool ret = napiLoopback->loopback_->SetEqualizerPreset(static_cast<AudioLoopbackEqualizerPreset>(preset));
591 napi_get_boolean(env, ret, &result);
592 return result;
593 }
594
GetEqualizerPreset(napi_env env,napi_callback_info info)595 napi_value NapiAudioLoopback::GetEqualizerPreset(napi_env env, napi_callback_info info)
596 {
597 size_t argc = PARAM0;
598 NapiAudioLoopback *napiLoopback = GetParamWithSync(env, info, argc, nullptr);
599 CHECK_AND_RETURN_RET_LOG(napiLoopback != nullptr,
600 NapiAudioError::ThrowErrorAndReturn(env, NAPI_ERR_NO_MEMORY), "napiLoopback is nullptr");
601 CHECK_AND_RETURN_RET_LOG(napiLoopback->loopback_ != nullptr, NapiAudioError::ThrowErrorAndReturn(env,
602 NAPI_ERR_NO_MEMORY), "loopback_ is nullptr");
603 int32_t reverbPreset = static_cast<int32_t>(napiLoopback->loopback_->GetEqualizerPreset());
604 napi_value result = nullptr;
605 napi_status status = NapiParamUtils::SetValueInt32(env, reverbPreset, result);
606 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "SetValueInt32 failed");
607 return result;
608 }
609 } // namespace AudioStandard
610 } // namespace OHOS
611