1 /*
2  * Copyright (c) 2023 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 "NapiAudioCapturerInfoChangeCallback"
17 #endif
18 
19 #include "napi_audio_capturer_info_change_callback.h"
20 #include "audio_errors.h"
21 #include "audio_capturer_log.h"
22 #include "napi_param_utils.h"
23 
24 namespace OHOS {
25 namespace AudioStandard {
NapiAudioCapturerInfoChangeCallback(napi_env env)26 NapiAudioCapturerInfoChangeCallback::NapiAudioCapturerInfoChangeCallback(napi_env env)
27     : env_(env)
28 {
29     AUDIO_DEBUG_LOG("Instance create");
30 }
31 
~NapiAudioCapturerInfoChangeCallback()32 NapiAudioCapturerInfoChangeCallback::~NapiAudioCapturerInfoChangeCallback()
33 {
34     AUDIO_DEBUG_LOG("Instance destroy");
35 }
36 
SaveCallbackReference(napi_value args)37 void NapiAudioCapturerInfoChangeCallback::SaveCallbackReference(napi_value args)
38 {
39     std::lock_guard<std::mutex> lock(mutex_);
40     napi_ref callback = nullptr;
41     const int32_t refCount = 1;
42 
43     napi_status status = napi_create_reference(env_, args, refCount, &callback);
44     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
45         "Creating reference for callback fail");
46 
47     callback_ = callback;
48 }
49 
ContainSameJsCallback(napi_value args)50 bool NapiAudioCapturerInfoChangeCallback::ContainSameJsCallback(napi_value args)
51 {
52     bool isEquals = false;
53     napi_value copyValue = nullptr;
54 
55     napi_get_reference_value(env_, callback_, &copyValue);
56     CHECK_AND_RETURN_RET_LOG(args != nullptr, false, "args is nullptr");
57 
58     CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env_, copyValue, args, &isEquals) == napi_ok, false,
59         "Get napi_strict_equals failed");
60 
61     return isEquals;
62 }
63 
OnStateChange(const AudioCapturerChangeInfo & capturerChangeInfo)64 void NapiAudioCapturerInfoChangeCallback::OnStateChange(const AudioCapturerChangeInfo &capturerChangeInfo)
65 {
66     OnJsCallbackCapturerChangeInfo(callback_, capturerChangeInfo);
67 }
68 
WorkCallbackCompleted(uv_work_t * work,int status)69 void NapiAudioCapturerInfoChangeCallback::WorkCallbackCompleted(uv_work_t *work, int status)
70 {
71     // Js Thread
72     std::shared_ptr<AudioCapturerChangeInfoJsCallback> context(
73         static_cast<AudioCapturerChangeInfoJsCallback*>(work->data),
74         [work](AudioCapturerChangeInfoJsCallback* ptr) {
75             delete ptr;
76             delete work;
77     });
78 
79     AudioCapturerChangeInfoJsCallback *event = reinterpret_cast<AudioCapturerChangeInfoJsCallback*>(work->data);
80     if (event == nullptr || event->callback_ == nullptr) {
81         AUDIO_ERR_LOG("OnJsCallbackCapturerChangeInfo: no memory");
82         return;
83     }
84     napi_env env = event->env_;
85     napi_ref callback = event->callback_;
86 
87     napi_handle_scope scope = nullptr;
88     napi_open_handle_scope(env, &scope);
89     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
90     do {
91         napi_value jsCallback = nullptr;
92         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
93         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "Callback get reference value fail");
94         // Call back function
95         napi_value args[ARGS_ONE] = { nullptr };
96         NapiParamUtils::SetAudioCapturerChangeInfoDescriptors(env, event->capturerChangeInfo_, args[0]);
97         CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
98             "Fail to convert to jsobj");
99 
100         const size_t argCount = ARGS_ONE;
101         napi_value result = nullptr;
102         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
103         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call capturer callback");
104     } while (0);
105     napi_close_handle_scope(env, scope);
106 }
107 
OnJsCallbackCapturerChangeInfo(napi_ref method,const AudioCapturerChangeInfo & capturerChangeInfo)108 void NapiAudioCapturerInfoChangeCallback::OnJsCallbackCapturerChangeInfo(napi_ref method,
109     const AudioCapturerChangeInfo &capturerChangeInfo)
110 {
111     uv_loop_s *loop = nullptr;
112     napi_get_uv_event_loop(env_, &loop);
113     CHECK_AND_RETURN_LOG(loop != nullptr, "Loop is nullptr");
114     CHECK_AND_RETURN_LOG(method != nullptr, "method is nullptr");
115 
116     uv_work_t *work = new(std::nothrow) uv_work_t;
117     CHECK_AND_RETURN_LOG(work != nullptr, "OnJsCallbackCapturerDeviceInfo: no memory");
118     work->data = new AudioCapturerChangeInfoJsCallback {method, env_, capturerChangeInfo};
119     if (work->data == nullptr) {
120         AUDIO_ERR_LOG("work data malloc failed: No memory");
121         delete work;
122         return;
123     }
124 
125     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, WorkCallbackCompleted);
126     if (ret != 0) {
127         AUDIO_ERR_LOG("Failed to execute libuv work queue");
128         if (work != nullptr) {
129             if (work->data != nullptr) {
130                 delete reinterpret_cast<AudioCapturerChangeInfoJsCallback*>(work->data);
131             }
132             delete work;
133         }
134     }
135 }
136 
137 }  // namespace AudioStandard
138 }  // namespace OHOS
139