• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "NapiAudioRoutingMgrCallbacks"
17 #endif
18 
19 #include "js_native_api.h"
20 #include "napi_audio_routing_manager_callbacks.h"
21 #include "napi_audio_enum.h"
22 #include "napi_audio_error.h"
23 #include "napi_param_utils.h"
24 #include "audio_errors.h"
25 #include "audio_manager_log.h"
26 #include "napi_audio_manager_callbacks.h"
27 
28 namespace OHOS {
29 namespace AudioStandard {
NapiAudioPreferredOutputDeviceChangeCallback(napi_env env)30 NapiAudioPreferredOutputDeviceChangeCallback::NapiAudioPreferredOutputDeviceChangeCallback(napi_env env)
31     : env_(env)
32 {
33     AUDIO_DEBUG_LOG("NapiAudioPreferredOutputDeviceChangeCallback: instance create");
34 }
35 
~NapiAudioPreferredOutputDeviceChangeCallback()36 NapiAudioPreferredOutputDeviceChangeCallback::~NapiAudioPreferredOutputDeviceChangeCallback()
37 {
38     if (regAmOutputDevChgTsfn_) {
39         napi_release_threadsafe_function(amOutputDevChgTsfn_, napi_tsfn_abort);
40     }
41     AUDIO_DEBUG_LOG("NapiAudioPreferredOutputDeviceChangeCallback: instance destroy");
42 }
43 
CreatePreferredOutTsfn(napi_env env)44 void NapiAudioPreferredOutputDeviceChangeCallback::CreatePreferredOutTsfn(napi_env env)
45 {
46     regAmOutputDevChgTsfn_ = true;
47     napi_value cbName;
48     std::string callbackName = "PreferredOutputDeviceChange";
49     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
50     napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr,
51         ActiveOutputDeviceChangeTsfnFinalize, nullptr, SafeJsCallbackActiveOutputDeviceChangeWork,
52         &amOutputDevChgTsfn_);
53 }
54 
GetPreferredOutTsfnFlag()55 bool NapiAudioPreferredOutputDeviceChangeCallback::GetPreferredOutTsfnFlag()
56 {
57     return regAmOutputDevChgTsfn_;
58 }
59 
SaveCallbackReference(napi_value callback)60 void NapiAudioPreferredOutputDeviceChangeCallback::SaveCallbackReference(napi_value callback)
61 {
62     napi_ref callbackRef = nullptr;
63     const int32_t refCount = ARGS_ONE;
64 
65     napi_status status = napi_create_reference(env_, callback, refCount, &callbackRef);
66     CHECK_AND_RETURN_LOG(status == napi_ok && callbackRef != nullptr,
67         "SaveCallbackReference: creating reference for callback fail");
68     callback_ = std::make_shared<AutoRef>(env_, callbackRef);
69 }
70 
OnPreferredOutputDeviceUpdated(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> & desc)71 void NapiAudioPreferredOutputDeviceChangeCallback::OnPreferredOutputDeviceUpdated(
72     const std::vector<std::shared_ptr<AudioDeviceDescriptor>> &desc)
73 {
74     std::unique_ptr<AudioActiveOutputDeviceChangeJsCallback> cb =
75         std::make_unique<AudioActiveOutputDeviceChangeJsCallback>();
76     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
77 
78     cb->callback = callback_;
79     cb->callbackName = PREFERRED_OUTPUT_DEVICE_CALLBACK_NAME;
80     cb->desc = desc;
81     OnJsCallbackActiveOutputDeviceChange(cb);
82     return;
83 }
84 
SafeJsCallbackActiveOutputDeviceChangeWork(napi_env env,napi_value js_cb,void * context,void * data)85 void NapiAudioPreferredOutputDeviceChangeCallback::SafeJsCallbackActiveOutputDeviceChangeWork(
86     napi_env env, napi_value js_cb, void *context, void *data)
87 {
88     AudioActiveOutputDeviceChangeJsCallback *event = reinterpret_cast<AudioActiveOutputDeviceChangeJsCallback *>(data);
89     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
90         "OnJsCallbackActiveOutputDeviceChange: no memory");
91     std::shared_ptr<AudioActiveOutputDeviceChangeJsCallback> safeContext(
92         static_cast<AudioActiveOutputDeviceChangeJsCallback*>(data),
93         [](AudioActiveOutputDeviceChangeJsCallback *ptr) {
94             delete ptr;
95     });
96     std::string request = event->callbackName;
97     napi_ref callback = event->callback->cb_;
98     napi_handle_scope scope = nullptr;
99     napi_open_handle_scope(env, &scope);
100     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
101     AUDIO_INFO_LOG("SafeJsCallbackActiveOutputDeviceChangeWork: safe js callback working.");
102 
103     do {
104         napi_value jsCallback = nullptr;
105         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
106         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
107             request.c_str());
108 
109         // Call back function
110         napi_value args[ARGS_ONE] = { nullptr };
111         NapiParamUtils::SetDeviceDescriptors(env, event->desc, args[PARAM0]);
112         CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
113             "%{public}s fail to create ringer mode callback", request.c_str());
114 
115         const size_t argCount = ARGS_ONE;
116         napi_value result = nullptr;
117         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
118         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call ringer mode callback", request.c_str());
119     } while (0);
120     napi_close_handle_scope(env, scope);
121 }
122 
ActiveOutputDeviceChangeTsfnFinalize(napi_env env,void * data,void * hint)123 void NapiAudioPreferredOutputDeviceChangeCallback::ActiveOutputDeviceChangeTsfnFinalize(
124     napi_env env, void *data, void *hint)
125 {
126     AUDIO_INFO_LOG("RingModeTsfnFinalize: safe thread resource release.");
127 }
128 
OnJsCallbackActiveOutputDeviceChange(std::unique_ptr<AudioActiveOutputDeviceChangeJsCallback> & jsCb)129 void NapiAudioPreferredOutputDeviceChangeCallback::OnJsCallbackActiveOutputDeviceChange(
130     std::unique_ptr<AudioActiveOutputDeviceChangeJsCallback> &jsCb)
131 {
132     if (jsCb.get() == nullptr) {
133         AUDIO_ERR_LOG("OnJsCallbackDeviceChange: jsCb.get() is null");
134         return;
135     }
136 
137     AudioActiveOutputDeviceChangeJsCallback *event = jsCb.release();
138     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
139 
140     napi_acquire_threadsafe_function(amOutputDevChgTsfn_);
141     napi_call_threadsafe_function(amOutputDevChgTsfn_, event, napi_tsfn_blocking);
142 }
143 
ContainSameJsCallback(napi_value args)144 bool NapiAudioPreferredOutputDeviceChangeCallback::ContainSameJsCallback(napi_value args)
145 {
146     bool isEquals = false;
147     napi_value copyValue = nullptr;
148 
149     napi_get_reference_value(env_, callback_->cb_, &copyValue);
150     CHECK_AND_RETURN_RET_LOG(args != nullptr, false, "args is nullptr");
151 
152     CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env_, copyValue, args, &isEquals) == napi_ok, false,
153         "Get napi_strict_equals failed");
154 
155     return isEquals;
156 }
157 
NapiAudioPreferredInputDeviceChangeCallback(napi_env env)158 NapiAudioPreferredInputDeviceChangeCallback::NapiAudioPreferredInputDeviceChangeCallback(napi_env env)
159     : env_(env)
160 {
161     AUDIO_DEBUG_LOG("NapiAudioPreferredInputDeviceChangeCallback: instance create");
162 }
163 
~NapiAudioPreferredInputDeviceChangeCallback()164 NapiAudioPreferredInputDeviceChangeCallback::~NapiAudioPreferredInputDeviceChangeCallback()
165 {
166     if (regAmInputDevChgTsfn_) {
167         napi_release_threadsafe_function(amInputDevChgTsfn_, napi_tsfn_abort);
168     }
169     AUDIO_DEBUG_LOG("NapiAudioPreferredInputDeviceChangeCallback: instance destroy");
170 }
171 
SaveCallbackReference(napi_value callback)172 void NapiAudioPreferredInputDeviceChangeCallback::SaveCallbackReference(napi_value callback)
173 {
174     napi_ref callbackRef = nullptr;
175     const int32_t refCount = ARGS_ONE;
176 
177     napi_status status = napi_create_reference(env_, callback, refCount, &callbackRef);
178     CHECK_AND_RETURN_LOG(status == napi_ok && callbackRef != nullptr,
179         "SaveCallbackReference: creating reference for callback fail");
180 
181     callback_ = std::make_shared<AutoRef>(env_, callbackRef);
182 }
183 
CreatePreferredInTsfn(napi_env env)184 void NapiAudioPreferredInputDeviceChangeCallback::CreatePreferredInTsfn(napi_env env)
185 {
186     regAmInputDevChgTsfn_ = true;
187     napi_value cbName;
188     std::string callbackName = "PreferredInputDeviceChange";
189     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
190     napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr,
191         ActiveInputDeviceChangeTsfnFinalize, nullptr, SafeJsCallbackActiveInputDeviceChangeWork,
192         &amInputDevChgTsfn_);
193 }
194 
GetPreferredInTsfnFlag()195 bool NapiAudioPreferredInputDeviceChangeCallback::GetPreferredInTsfnFlag()
196 {
197     return regAmInputDevChgTsfn_;
198 }
199 
OnPreferredInputDeviceUpdated(const std::vector<std::shared_ptr<AudioDeviceDescriptor>> & desc)200 void NapiAudioPreferredInputDeviceChangeCallback::OnPreferredInputDeviceUpdated(
201     const std::vector<std::shared_ptr<AudioDeviceDescriptor>> &desc)
202 {
203     std::unique_ptr<AudioActiveInputDeviceChangeJsCallback> cb =
204         std::make_unique<AudioActiveInputDeviceChangeJsCallback>();
205     CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
206 
207     cb->callback = callback_;
208     cb->callbackName = PREFERRED_INPUT_DEVICE_CALLBACK_NAME;
209     cb->desc = desc;
210     OnJsCallbackActiveInputDeviceChange(cb);
211     return;
212 }
213 
SafeJsCallbackActiveInputDeviceChangeWork(napi_env env,napi_value js_cb,void * context,void * data)214 void NapiAudioPreferredInputDeviceChangeCallback::SafeJsCallbackActiveInputDeviceChangeWork(
215     napi_env env, napi_value js_cb, void *context, void *data)
216 {
217     AudioActiveInputDeviceChangeJsCallback *event = reinterpret_cast<AudioActiveInputDeviceChangeJsCallback *>(data);
218     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
219         "OnJsCallbackActiveInputDeviceChange: no memory");
220     std::shared_ptr<AudioActiveInputDeviceChangeJsCallback> safeContext(
221         static_cast<AudioActiveInputDeviceChangeJsCallback*>(data),
222         [](AudioActiveInputDeviceChangeJsCallback *ptr) {
223             delete ptr;
224     });
225     std::string request = event->callbackName;
226     napi_ref callback = event->callback->cb_;
227     napi_handle_scope scope = nullptr;
228     napi_open_handle_scope(env, &scope);
229     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
230     do {
231         napi_value jsCallback = nullptr;
232         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
233         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
234             request.c_str());
235 
236         // Call back function
237         napi_value args[ARGS_ONE] = { nullptr };
238         NapiParamUtils::SetDeviceDescriptors(env, event->desc, args[PARAM0]);
239         CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr,
240             "%{public}s fail to create input device change callback", request.c_str());
241 
242         const size_t argCount = ARGS_ONE;
243         napi_value result = nullptr;
244         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
245         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call device change callback", request.c_str());
246     } while (0);
247     napi_close_handle_scope(env, scope);
248 }
249 
ActiveInputDeviceChangeTsfnFinalize(napi_env env,void * data,void * hint)250 void NapiAudioPreferredInputDeviceChangeCallback::ActiveInputDeviceChangeTsfnFinalize(
251     napi_env env, void *data, void *hint)
252 {
253     AUDIO_INFO_LOG("ActiveInputDeviceChangeTsfnFinalize: safe thread resource release.");
254 }
255 
OnJsCallbackActiveInputDeviceChange(std::unique_ptr<AudioActiveInputDeviceChangeJsCallback> & jsCb)256 void NapiAudioPreferredInputDeviceChangeCallback::OnJsCallbackActiveInputDeviceChange(
257     std::unique_ptr<AudioActiveInputDeviceChangeJsCallback> &jsCb)
258 {
259     if (jsCb.get() == nullptr) {
260         AUDIO_ERR_LOG("OnJsCallbackDeviceChange: jsCb.get() is null");
261         return;
262     }
263 
264     AudioActiveInputDeviceChangeJsCallback *event = jsCb.release();
265     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
266 
267     napi_acquire_threadsafe_function(amInputDevChgTsfn_);
268     napi_call_threadsafe_function(amInputDevChgTsfn_, event, napi_tsfn_blocking);
269 }
270 
ContainSameJsCallback(napi_value args)271 bool NapiAudioPreferredInputDeviceChangeCallback::ContainSameJsCallback(napi_value args)
272 {
273     bool isEquals = false;
274     napi_value copyValue = nullptr;
275 
276     napi_get_reference_value(env_, callback_->cb_, &copyValue);
277     CHECK_AND_RETURN_RET_LOG(args != nullptr, false, "args is nullptr");
278 
279     CHECK_AND_RETURN_RET_LOG(napi_strict_equals(env_, copyValue, args, &isEquals) == napi_ok, false,
280         "Get napi_strict_equals failed");
281 
282     return isEquals;
283 }
284 }  // namespace AudioStandard
285 }  // namespace OHOS
286