• 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 "NapiAudioSpatializationMgrCallback"
17 #endif
18 
19 #include "js_native_api.h"
20 #include "napi_audio_spatialization_manager_callback.h"
21 #include "audio_errors.h"
22 #include "audio_manager_log.h"
23 #include "napi_param_utils.h"
24 #include "napi_audio_error.h"
25 #include "napi_audio_manager_callbacks.h"
26 
27 namespace OHOS {
28 namespace AudioStandard {
29 bool NapiAudioSpatializationEnabledChangeCallback::onSpatializationEnabledChangeFlag_;
30 bool NapiAudioHeadTrackingEnabledChangeCallback::onHeadTrackingEnabledChangeFlag_;
31 using namespace std;
NapiAudioSpatializationEnabledChangeCallback(napi_env env)32 NapiAudioSpatializationEnabledChangeCallback::NapiAudioSpatializationEnabledChangeCallback(napi_env env)
33     : env_(env)
34 {
35     AUDIO_DEBUG_LOG("NapiAudioSpatializationEnabledChangeCallback: instance create");
36 }
37 
~NapiAudioSpatializationEnabledChangeCallback()38 NapiAudioSpatializationEnabledChangeCallback::~NapiAudioSpatializationEnabledChangeCallback()
39 {
40     if (regAmSpatEnable_) {
41         napi_release_threadsafe_function(amSpatEnableTsfn_, napi_tsfn_abort);
42     }
43     AUDIO_DEBUG_LOG("NapiAudioSpatializationEnabledChangeCallback: instance destroy");
44 }
45 
CreateSpatEnableTsfn(napi_env env)46 void NapiAudioSpatializationEnabledChangeCallback::CreateSpatEnableTsfn(napi_env env)
47 {
48     napi_value cbName;
49     regAmSpatEnable_ = true;
50     std::string callbackName = "volumeChange";
51     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
52     napi_create_threadsafe_function(env_, nullptr, nullptr, cbName, 0, 1, nullptr,
53         SpatializationEnabledTsfnFinalize, nullptr, SafeJsCallbackSpatializationEnabledWork,
54         &amSpatEnableTsfn_);
55 }
56 
GetSpatEnableTsfnFlag()57 bool NapiAudioSpatializationEnabledChangeCallback::GetSpatEnableTsfnFlag()
58 {
59     return regAmSpatEnable_;
60 }
61 
SaveSpatializationEnabledChangeCallbackReference(napi_value args,const std::string & cbName)62 void NapiAudioSpatializationEnabledChangeCallback::SaveSpatializationEnabledChangeCallbackReference(napi_value args,
63     const std::string &cbName)
64 {
65     std::lock_guard<std::mutex> lock(mutex_);
66     napi_ref callback = nullptr;
67     const int32_t refCount = ARGS_ONE;
68 
69     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
70         for (auto it = spatializationEnabledChangeCbList_.begin();
71             it != spatializationEnabledChangeCbList_.end(); ++it) {
72             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
73             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
74         }
75 
76         napi_status status = napi_create_reference(env_, args, refCount, &callback);
77         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
78             "NapiAudioSpatializationEnabledChangeCallback: creating reference for callback fail");
79 
80         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
81         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioSpatializationEnabledChangeCallback: creating callback failed");
82         spatializationEnabledChangeCbList_.push_back(cb);
83     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
84         for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
85             it != spatializationEnabledChangeCbForAnyDeviceList_.end(); ++it) {
86             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
87             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
88         }
89 
90         napi_status status = napi_create_reference(env_, args, refCount, &callback);
91         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
92             "NapiAudioSpatializationEnabledChangeCallback: creating reference for callback fail");
93 
94         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
95         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioSpatializationEnabledChangeCallback: creating callback failed");
96         spatializationEnabledChangeCbForAnyDeviceList_.push_back(cb);
97     }
98 }
99 
RemoveSpatializationEnabledChangeCallbackReference(napi_env env,napi_value args,const std::string & cbName)100 void NapiAudioSpatializationEnabledChangeCallback::RemoveSpatializationEnabledChangeCallbackReference(napi_env env,
101     napi_value args, const std::string &cbName)
102 {
103     std::lock_guard<std::mutex> lock(mutex_);
104     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
105         for (auto it = spatializationEnabledChangeCbList_.begin();
106             it != spatializationEnabledChangeCbList_.end(); ++it) {
107             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
108             if (isSameCallback) {
109                 AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: find js callback, erase it");
110                 spatializationEnabledChangeCbList_.erase(it);
111                 return;
112             }
113         }
114     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
115         for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
116             it != spatializationEnabledChangeCbForAnyDeviceList_.end(); ++it) {
117             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
118             if (isSameCallback) {
119                 AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: find js callback, erase it");
120                 spatializationEnabledChangeCbForAnyDeviceList_.erase(it);
121                 return;
122             }
123         }
124     }
125     AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: js callback no find");
126 }
127 
RemoveAllSpatializationEnabledChangeCallbackReference(const std::string & cbName)128 void NapiAudioSpatializationEnabledChangeCallback::RemoveAllSpatializationEnabledChangeCallbackReference(
129     const std::string &cbName)
130 {
131     std::lock_guard<std::mutex> lock(mutex_);
132     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
133         spatializationEnabledChangeCbList_.clear();
134     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
135         spatializationEnabledChangeCbForAnyDeviceList_.clear();
136     }
137     AUDIO_INFO_LOG("RemoveAllSpatializationEnabledChangeCallbackReference: remove all js callbacks success");
138 }
139 
GetSpatializationEnabledChangeCbListSize(const std::string & cbName)140 int32_t NapiAudioSpatializationEnabledChangeCallback::GetSpatializationEnabledChangeCbListSize(
141     const std::string &cbName)
142 {
143     std::lock_guard<std::mutex> lock(mutex_);
144     return ((!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) ? spatializationEnabledChangeCbList_.size():
145         spatializationEnabledChangeCbForAnyDeviceList_.size());
146 }
147 
OnSpatializationEnabledChange(const bool & enabled)148 void NapiAudioSpatializationEnabledChangeCallback::OnSpatializationEnabledChange(const bool &enabled)
149 {
150     AUDIO_INFO_LOG("OnSpatializationEnabledChange entered");
151     std::lock_guard<std::mutex> lock(mutex_);
152 
153     for (auto it = spatializationEnabledChangeCbList_.begin(); it != spatializationEnabledChangeCbList_.end(); it++) {
154         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
155             std::make_unique<AudioSpatializationEnabledJsCallback>();
156         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
157         cb->callback = (*it);
158         cb->enabled = enabled;
159         onSpatializationEnabledChangeFlag_ = true;
160         OnJsCallbackSpatializationEnabled(cb);
161     }
162     return;
163 }
164 
OnSpatializationEnabledChangeForAnyDevice(const std::shared_ptr<AudioDeviceDescriptor> & deviceDescriptor,const bool & enabled)165 void NapiAudioSpatializationEnabledChangeCallback::OnSpatializationEnabledChangeForAnyDevice(
166     const std::shared_ptr<AudioDeviceDescriptor> &deviceDescriptor, const bool &enabled)
167 {
168     AUDIO_INFO_LOG("OnSpatializationEnabledChange by the speified device entered");
169     std::lock_guard<std::mutex> lock(mutex_);
170 
171     for (auto it = spatializationEnabledChangeCbList_.begin(); it != spatializationEnabledChangeCbList_.end(); it++) {
172         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
173             std::make_unique<AudioSpatializationEnabledJsCallback>();
174         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
175         cb->callback = (*it);
176         cb->enabled = enabled;
177         onSpatializationEnabledChangeFlag_ = true;
178         OnJsCallbackSpatializationEnabled(cb);
179     }
180     for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
181         it != spatializationEnabledChangeCbForAnyDeviceList_.end(); it++) {
182         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
183             std::make_unique<AudioSpatializationEnabledJsCallback>();
184         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
185         cb->callback = (*it);
186         cb->deviceDescriptor = deviceDescriptor;
187         cb->enabled = enabled;
188         onSpatializationEnabledChangeFlag_ = false;
189         OnJsCallbackSpatializationEnabled(cb);
190     }
191 
192     return;
193 }
194 
SafeJsCallbackSpatializationEnabledWork(napi_env env,napi_value js_cb,void * context,void * data)195 void NapiAudioSpatializationEnabledChangeCallback::SafeJsCallbackSpatializationEnabledWork(
196     napi_env env, napi_value js_cb, void *context, void *data)
197 {
198     AudioSpatializationEnabledJsCallback *event = reinterpret_cast<AudioSpatializationEnabledJsCallback *>(data);
199     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
200         "OnJsCallbackSpatializationEnabled: no memory");
201     std::shared_ptr<AudioSpatializationEnabledJsCallback> safeContext(
202         static_cast<AudioSpatializationEnabledJsCallback*>(data),
203         [](AudioSpatializationEnabledJsCallback *ptr) {
204             delete ptr;
205     });
206     napi_ref callback = event->callback->cb_;
207     napi_handle_scope scope = nullptr;
208     napi_open_handle_scope(env, &scope);
209     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
210     AUDIO_INFO_LOG("SafeJsCallbackSpatializationEnabledWork: safe js callback working.");
211 
212     do {
213         napi_value jsCallback = nullptr;
214         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
215         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "callback get reference value fail");
216         napi_value args[ARGS_ONE] = { nullptr };
217         const size_t argCount = ARGS_ONE;
218         napi_value result = nullptr;
219 
220         if (onSpatializationEnabledChangeFlag_) {
221             NapiParamUtils::SetValueBoolean(env, event->enabled, args[PARAM0]);
222             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
223         } else {
224             AudioSpatialEnabledStateForDevice audioSpatialEnabledStateForDevice;
225             audioSpatialEnabledStateForDevice.deviceDescriptor = event->deviceDescriptor;
226             audioSpatialEnabledStateForDevice.enabled = event->enabled;
227             NapiParamUtils::SetAudioSpatialEnabledStateForDevice(env,
228                 audioSpatialEnabledStateForDevice, args[PARAM0]);
229             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
230         }
231 
232         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
233         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call spatialization enabled callback");
234     } while (0);
235     napi_close_handle_scope(env, scope);
236 }
237 
SpatializationEnabledTsfnFinalize(napi_env env,void * data,void * hint)238 void NapiAudioSpatializationEnabledChangeCallback::SpatializationEnabledTsfnFinalize(
239     napi_env env, void *data, void *hint)
240 {
241     AUDIO_INFO_LOG("SpatializationEnabledTsfnFinalize: safe thread resource release.");
242 }
243 
OnJsCallbackSpatializationEnabled(std::unique_ptr<AudioSpatializationEnabledJsCallback> & jsCb)244 void NapiAudioSpatializationEnabledChangeCallback::OnJsCallbackSpatializationEnabled(
245     std::unique_ptr<AudioSpatializationEnabledJsCallback> &jsCb)
246 {
247     if (jsCb.get() == nullptr) {
248         AUDIO_ERR_LOG("OnJsCallbackSpatializationEnabled: jsCb.get() is null");
249         return;
250     }
251 
252     AudioSpatializationEnabledJsCallback *event = jsCb.release();
253     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
254     event->callbackName = "AudioSpatializationEnabled";
255 
256     napi_acquire_threadsafe_function(amSpatEnableTsfn_);
257     napi_call_threadsafe_function(amSpatEnableTsfn_, event, napi_tsfn_blocking);
258 }
259 
NapiAudioCurrentSpatializationEnabledChangeCallback(napi_env env)260 NapiAudioCurrentSpatializationEnabledChangeCallback::NapiAudioCurrentSpatializationEnabledChangeCallback(
261     napi_env env) : env_(env)
262 {
263     AUDIO_DEBUG_LOG("NapiAudioCurrentSpatializationEnabledChangeCallback: instance create");
264 }
265 
~NapiAudioCurrentSpatializationEnabledChangeCallback()266 NapiAudioCurrentSpatializationEnabledChangeCallback::~NapiAudioCurrentSpatializationEnabledChangeCallback()
267 {
268     if (regAmSpatEnableForCurrentDevice_) {
269         napi_release_threadsafe_function(amSpatEnableForCurrentDeviceTsfn_, napi_tsfn_abort);
270     }
271     AUDIO_DEBUG_LOG("NapiAudioCurrentSpatializationEnabledChangeCallback: instance destroy");
272 }
273 
SaveCurrentSpatializationEnabledChangeCallbackReference(napi_value args,const std::string & cbName)274 void NapiAudioCurrentSpatializationEnabledChangeCallback::SaveCurrentSpatializationEnabledChangeCallbackReference(
275     napi_value args, const std::string &cbName)
276 {
277     std::lock_guard<std::mutex> lock(mutex_);
278     napi_ref callback = nullptr;
279     const int32_t refCount = ARGS_ONE;
280     for (auto it = spatializationEnabledChangeCbForCurrentDeviceList_.begin();
281         it != spatializationEnabledChangeCbForCurrentDeviceList_.end(); ++it) {
282         bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
283         CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
284     }
285 
286     napi_status status = napi_create_reference(env_, args, refCount, &callback);
287     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
288         "NapiAudioCurrentSpatializationEnabledChangeCallback: creating reference for callback fail");
289 
290     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
291     CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioCurrentSpatializationEnabledChangeCallback:creating callback failed");
292 
293     spatializationEnabledChangeCbForCurrentDeviceList_.push_back(cb);
294 }
295 
CreateCurrentSpatEnableForCurrentDeviceTsfn(napi_env env)296 void NapiAudioCurrentSpatializationEnabledChangeCallback::CreateCurrentSpatEnableForCurrentDeviceTsfn(napi_env env)
297 {
298     regAmSpatEnableForCurrentDevice_ = true;
299     napi_value cbName;
300     std::string callbackName = "AudioSpatializationEnabledForCurrentDevice";
301     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
302     napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr,
303         SpatializationEnabledForCurrentDeviceTsfnFinalize, nullptr,
304         SafeJsCallbackSpatializationEnabledForCurrentDeviceWork, &amSpatEnableForCurrentDeviceTsfn_);
305 }
306 
GetCurrentSpatEnableForCurrentDeviceTsfnFlag()307 bool NapiAudioCurrentSpatializationEnabledChangeCallback::GetCurrentSpatEnableForCurrentDeviceTsfnFlag()
308 {
309     return regAmSpatEnableForCurrentDevice_;
310 }
311 
RemoveCurrentSpatializationEnabledChangeCallbackReference(napi_env env,napi_value args,const std::string & cbName)312 void NapiAudioCurrentSpatializationEnabledChangeCallback::RemoveCurrentSpatializationEnabledChangeCallbackReference(
313     napi_env env, napi_value args, const std::string &cbName)
314 {
315     std::lock_guard<std::mutex> lock(mutex_);
316     for (auto it = spatializationEnabledChangeCbForCurrentDeviceList_.begin();
317         it != spatializationEnabledChangeCbForCurrentDeviceList_.end(); ++it) {
318         bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
319         if (isSameCallback) {
320             AUDIO_INFO_LOG("RemoveCurrentSpatializationEnabledChangeCallbackReference: find js callback,"
321                 "erase it");
322             spatializationEnabledChangeCbForCurrentDeviceList_.erase(it);
323             return;
324         }
325     }
326     AUDIO_INFO_LOG("RemoveCurrentSpatializationEnabledChangeCallbackReference: js callback no find");
327 }
328 
RemoveAllCurrentSpatializationEnabledChangeCallbackReference(const std::string & cbName)329 void NapiAudioCurrentSpatializationEnabledChangeCallback::RemoveAllCurrentSpatializationEnabledChangeCallbackReference(
330     const std::string &cbName)
331 {
332     std::lock_guard<std::mutex> lock(mutex_);
333     spatializationEnabledChangeCbForCurrentDeviceList_.clear();
334 
335     AUDIO_INFO_LOG("RemoveAllCurrentSpatializationEnabledChangeCallbackReference: remove all js callbacks"
336         "success");
337 }
338 
GetCurrentSpatializationEnabledChangeCbListSize(const std::string & cbName)339 int32_t NapiAudioCurrentSpatializationEnabledChangeCallback::GetCurrentSpatializationEnabledChangeCbListSize(
340     const std::string &cbName)
341 {
342     std::lock_guard<std::mutex> lock(mutex_);
343     return spatializationEnabledChangeCbForCurrentDeviceList_.size();
344 }
345 
OnSpatializationEnabledChangeForCurrentDevice(const bool & enabled)346 void NapiAudioCurrentSpatializationEnabledChangeCallback::OnSpatializationEnabledChangeForCurrentDevice(
347     const bool &enabled)
348 {
349     AUDIO_INFO_LOG("OnSpatializationEnabledChangeForCurrentDevice entered");
350     std::lock_guard<std::mutex> lock(mutex_);
351 
352     for (auto it = spatializationEnabledChangeCbForCurrentDeviceList_.begin();
353         it != spatializationEnabledChangeCbForCurrentDeviceList_.end(); it++) {
354         std::unique_ptr<AudioSpatializationEnabledForCurrentDeviceJsCallback> cb =
355             std::make_unique<AudioSpatializationEnabledForCurrentDeviceJsCallback>();
356         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
357         cb->callback = (*it);
358         cb->enabled = enabled;
359         OnJsCallbackSpatializationEnabledForCurrentDevice(cb);
360     }
361 
362     return;
363 }
364 
SafeJsCallbackSpatializationEnabledForCurrentDeviceWork(napi_env env,napi_value js_cb,void * context,void * data)365 void NapiAudioCurrentSpatializationEnabledChangeCallback::SafeJsCallbackSpatializationEnabledForCurrentDeviceWork(
366     napi_env env, napi_value js_cb, void *context, void *data)
367 {
368     AudioSpatializationEnabledForCurrentDeviceJsCallback *event =
369         reinterpret_cast<AudioSpatializationEnabledForCurrentDeviceJsCallback *>(data);
370     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
371         "OnJsCallbackSpatializationEnabledForCurrentDevice: no memory");
372     std::shared_ptr<AudioSpatializationEnabledForCurrentDeviceJsCallback> safeContext(
373         static_cast<AudioSpatializationEnabledForCurrentDeviceJsCallback*>(data),
374         [](AudioSpatializationEnabledForCurrentDeviceJsCallback *ptr) {
375             delete ptr;
376     });
377     napi_ref callback = event->callback->cb_;
378     napi_handle_scope scope = nullptr;
379     napi_open_handle_scope(env, &scope);
380     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
381     AUDIO_INFO_LOG("SafeJsCallbackSpatializationEnabledForCurrentDeviceWork: safe js callback working.");
382 
383     do {
384         napi_value jsCallback = nullptr;
385         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
386         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "callback get reference value fail");
387         napi_value args[ARGS_ONE] = { nullptr };
388         NapiParamUtils::SetValueBoolean(env, event->enabled, args[PARAM0]);
389         CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
390 
391         const size_t argCount = ARGS_ONE;
392         napi_value result = nullptr;
393 
394         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
395         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call head tracking enabled callback");
396     } while (0);
397     napi_close_handle_scope(env, scope);
398 }
399 
SpatializationEnabledForCurrentDeviceTsfnFinalize(napi_env env,void * data,void * hint)400 void NapiAudioCurrentSpatializationEnabledChangeCallback::SpatializationEnabledForCurrentDeviceTsfnFinalize(
401     napi_env env, void *data, void *hint)
402 {
403     AUDIO_INFO_LOG("SpatializationEnabledForCurrentDeviceTsfnFinalize: safe thread resource release.");
404 }
405 
OnJsCallbackSpatializationEnabledForCurrentDevice(std::unique_ptr<AudioSpatializationEnabledForCurrentDeviceJsCallback> & jsCb)406 void NapiAudioCurrentSpatializationEnabledChangeCallback::OnJsCallbackSpatializationEnabledForCurrentDevice(
407     std::unique_ptr<AudioSpatializationEnabledForCurrentDeviceJsCallback> &jsCb)
408 {
409     if (jsCb.get() == nullptr) {
410         AUDIO_ERR_LOG("OnJsCallbackSpatializationEnabledForCurrentDevice: jsCb.get() is null");
411         return;
412     }
413 
414     AudioSpatializationEnabledForCurrentDeviceJsCallback *event = jsCb.release();
415     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
416 
417     napi_acquire_threadsafe_function(amSpatEnableForCurrentDeviceTsfn_);
418     napi_call_threadsafe_function(amSpatEnableForCurrentDeviceTsfn_, event, napi_tsfn_blocking);
419 }
420 
NapiAudioHeadTrackingEnabledChangeCallback(napi_env env)421 NapiAudioHeadTrackingEnabledChangeCallback::NapiAudioHeadTrackingEnabledChangeCallback(napi_env env)
422     : env_(env)
423 {
424     AUDIO_DEBUG_LOG("NapiAudioHeadTrackingEnabledChangeCallback: instance create");
425 }
426 
~NapiAudioHeadTrackingEnabledChangeCallback()427 NapiAudioHeadTrackingEnabledChangeCallback::~NapiAudioHeadTrackingEnabledChangeCallback()
428 {
429     if (regAmHeadTrkTsfn_) {
430         napi_release_threadsafe_function(amHeadTrkTsfn_, napi_tsfn_abort);
431     }
432     AUDIO_DEBUG_LOG("NapiAudioHeadTrackingEnabledChangeCallback: instance destroy");
433 }
434 
SaveHeadTrackingEnabledChangeCallbackReference(napi_value args,const std::string & cbName)435 void NapiAudioHeadTrackingEnabledChangeCallback::SaveHeadTrackingEnabledChangeCallbackReference(napi_value args,
436     const std::string &cbName)
437 {
438     std::lock_guard<std::mutex> lock(mutex_);
439     napi_ref callback = nullptr;
440     const int32_t refCount = ARGS_ONE;
441     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
442         for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); ++it) {
443             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
444             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
445         }
446 
447         napi_status status = napi_create_reference(env_, args, refCount, &callback);
448         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
449             "NapiAudioHeadTrackingEnabledChangeCallback: creating reference for callback fail");
450 
451         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
452         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioHeadTrackingEnabledChangeCallback: creating callback failed");
453 
454         headTrackingEnabledChangeCbList_.push_back(cb);
455     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
456         for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
457             it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); ++it) {
458             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
459             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
460         }
461 
462         napi_status status = napi_create_reference(env_, args, refCount, &callback);
463         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
464             "NapiAudioHeadTrackingEnabledChangeCallback: creating reference for callback fail");
465 
466         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
467         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioHeadTrackingEnabledChangeCallback: creating callback failed");
468 
469         headTrackingEnabledChangeCbForAnyDeviceList_.push_back(cb);
470     }
471 }
472 
CreateHeadTrackingTsfn(napi_env env)473 void NapiAudioHeadTrackingEnabledChangeCallback::CreateHeadTrackingTsfn(napi_env env)
474 {
475     regAmHeadTrkTsfn_ = true;
476     napi_value cbName;
477     std::string callbackName = "AudioHeadTrackingEnabled";
478     napi_create_string_utf8(env, callbackName.c_str(), callbackName.length(), &cbName);
479     napi_create_threadsafe_function(env, nullptr, nullptr, cbName, 0, 1, nullptr,
480         HeadTrackingEnabledTsfnFinalize, nullptr, SafeJsCallbackHeadTrackingEnabledWork,
481         &amHeadTrkTsfn_);
482 }
483 
GetHeadTrackingTsfnFlag()484 bool NapiAudioHeadTrackingEnabledChangeCallback::GetHeadTrackingTsfnFlag()
485 {
486     return regAmHeadTrkTsfn_;
487 }
488 
RemoveHeadTrackingEnabledChangeCallbackReference(napi_env env,napi_value args,const std::string & cbName)489 void NapiAudioHeadTrackingEnabledChangeCallback::RemoveHeadTrackingEnabledChangeCallbackReference(napi_env env,
490     napi_value args, const std::string &cbName)
491 {
492     std::lock_guard<std::mutex> lock(mutex_);
493     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
494         for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); ++it) {
495             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
496             if (isSameCallback) {
497                 AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: find js callback, erase it");
498                 headTrackingEnabledChangeCbList_.erase(it);
499                 return;
500             }
501         }
502     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
503         for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
504             it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); ++it) {
505             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
506             if (isSameCallback) {
507                 AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: find js callback, erase it");
508                 headTrackingEnabledChangeCbForAnyDeviceList_.erase(it);
509                 return;
510             }
511         }
512     }
513     AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: js callback no find");
514 }
515 
RemoveAllHeadTrackingEnabledChangeCallbackReference(const std::string & cbName)516 void NapiAudioHeadTrackingEnabledChangeCallback::RemoveAllHeadTrackingEnabledChangeCallbackReference(const std::string
517     &cbName)
518 {
519     std::lock_guard<std::mutex> lock(mutex_);
520     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
521         headTrackingEnabledChangeCbList_.clear();
522     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
523         headTrackingEnabledChangeCbForAnyDeviceList_.clear();
524     }
525     AUDIO_INFO_LOG("RemoveAllHeadTrackingEnabledChangeCallbackReference: remove all js callbacks success");
526 }
527 
GetHeadTrackingEnabledChangeCbListSize(const std::string & cbName)528 int32_t NapiAudioHeadTrackingEnabledChangeCallback::GetHeadTrackingEnabledChangeCbListSize(const std::string &cbName)
529 {
530     std::lock_guard<std::mutex> lock(mutex_);
531     return ((!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) ? headTrackingEnabledChangeCbList_.size():
532         headTrackingEnabledChangeCbForAnyDeviceList_.size());
533 }
534 
OnHeadTrackingEnabledChange(const bool & enabled)535 void NapiAudioHeadTrackingEnabledChangeCallback::OnHeadTrackingEnabledChange(const bool &enabled)
536 {
537     AUDIO_INFO_LOG("OnHeadTrackingEnabledChange entered");
538     std::lock_guard<std::mutex> lock(mutex_);
539 
540     for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); it++) {
541         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
542             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
543         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
544         cb->callback = (*it);
545         cb->enabled = enabled;
546         onHeadTrackingEnabledChangeFlag_ = true;
547         OnJsCallbackHeadTrackingEnabled(cb);
548     }
549 
550     return;
551 }
552 
OnHeadTrackingEnabledChangeForAnyDevice(const std::shared_ptr<AudioDeviceDescriptor> & deviceDescriptor,const bool & enabled)553 void NapiAudioHeadTrackingEnabledChangeCallback::OnHeadTrackingEnabledChangeForAnyDevice(
554     const std::shared_ptr<AudioDeviceDescriptor> &deviceDescriptor, const bool &enabled)
555 {
556     AUDIO_INFO_LOG("OnHeadTrackingEnabledChange by the specified device entered");
557     std::lock_guard<std::mutex> lock(mutex_);
558 
559     for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); it++) {
560         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
561             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
562         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
563         cb->callback = (*it);
564         cb->enabled = enabled;
565         onHeadTrackingEnabledChangeFlag_ = true;
566         OnJsCallbackHeadTrackingEnabled(cb);
567     }
568     for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
569         it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); it++) {
570         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
571             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
572         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
573         cb->callback = (*it);
574         cb->deviceDescriptor = deviceDescriptor;
575         cb->enabled = enabled;
576         onHeadTrackingEnabledChangeFlag_ = false;
577         OnJsCallbackHeadTrackingEnabled(cb);
578     }
579 
580     return;
581 }
582 
SafeJsCallbackHeadTrackingEnabledWork(napi_env env,napi_value js_cb,void * context,void * data)583 void NapiAudioHeadTrackingEnabledChangeCallback::SafeJsCallbackHeadTrackingEnabledWork(
584     napi_env env, napi_value js_cb, void *context, void *data)
585 {
586     AudioHeadTrackingEnabledJsCallback *event = reinterpret_cast<AudioHeadTrackingEnabledJsCallback *>(data);
587     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr),
588         "OnJsCallbackHeadTrackingEnabled: no memory");
589     std::shared_ptr<AudioHeadTrackingEnabledJsCallback> safeContext(
590         static_cast<AudioHeadTrackingEnabledJsCallback*>(data),
591         [](AudioHeadTrackingEnabledJsCallback *ptr) {
592             delete ptr;
593     });
594     napi_ref callback = event->callback->cb_;
595     napi_handle_scope scope = nullptr;
596     napi_open_handle_scope(env, &scope);
597     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
598     AUDIO_INFO_LOG("SafeJsCallbackHeadTrackingEnabledWork: safe js callback working.");
599 
600     do {
601         napi_value jsCallback = nullptr;
602         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
603         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "callback get reference value fail");
604         napi_value args[ARGS_ONE] = { nullptr };
605         const size_t argCount = ARGS_ONE;
606         napi_value result = nullptr;
607 
608         if (onHeadTrackingEnabledChangeFlag_) {
609             NapiParamUtils::SetValueBoolean(env, event->enabled, args[PARAM0]);
610             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
611         } else {
612             AudioSpatialEnabledStateForDevice audioSpatialEnabledStateForDevice;
613             audioSpatialEnabledStateForDevice.deviceDescriptor = event->deviceDescriptor;
614             audioSpatialEnabledStateForDevice.enabled = event->enabled;
615             NapiParamUtils::SetAudioSpatialEnabledStateForDevice(env,
616                 audioSpatialEnabledStateForDevice, args[PARAM0]);
617             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
618         }
619         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
620         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call head tracking enabled callback");
621     } while (0);
622     napi_close_handle_scope(env, scope);
623 }
624 
HeadTrackingEnabledTsfnFinalize(napi_env env,void * data,void * hint)625 void NapiAudioHeadTrackingEnabledChangeCallback::HeadTrackingEnabledTsfnFinalize(napi_env env, void *data, void *hint)
626 {
627     AUDIO_INFO_LOG("HeadTrackingEnabledTsfnFinalize: safe thread resource release.");
628 }
629 
OnJsCallbackHeadTrackingEnabled(std::unique_ptr<AudioHeadTrackingEnabledJsCallback> & jsCb)630 void NapiAudioHeadTrackingEnabledChangeCallback::OnJsCallbackHeadTrackingEnabled(
631     std::unique_ptr<AudioHeadTrackingEnabledJsCallback> &jsCb)
632 {
633     if (jsCb.get() == nullptr) {
634         AUDIO_ERR_LOG("OnJsCallbackHeadTrackingEnabled: jsCb.get() is null");
635         return;
636     }
637 
638     AudioHeadTrackingEnabledJsCallback *event = jsCb.release();
639     CHECK_AND_RETURN_LOG((event != nullptr) && (event->callback != nullptr), "event is nullptr.");
640 
641     napi_acquire_threadsafe_function(amHeadTrkTsfn_);
642     napi_call_threadsafe_function(amHeadTrkTsfn_, event, napi_tsfn_blocking);
643 }
644 } // namespace AudioStandard
645 } // namespace OHOS