• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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], &paramArg1);
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