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 "napi_audio_spatialization_manager_callback.h"
20 #include "audio_errors.h"
21 #include "audio_manager_log.h"
22 #include "napi_param_utils.h"
23 #include "napi_audio_error.h"
24 #include "napi_audio_manager_callbacks.h"
25 
26 namespace OHOS {
27 namespace AudioStandard {
28 bool NapiAudioSpatializationEnabledChangeCallback::onSpatializationEnabledChangeFlag_;
29 bool NapiAudioHeadTrackingEnabledChangeCallback::onHeadTrackingEnabledChangeFlag_;
30 using namespace std;
NapiAudioSpatializationEnabledChangeCallback(napi_env env)31 NapiAudioSpatializationEnabledChangeCallback::NapiAudioSpatializationEnabledChangeCallback(napi_env env)
32     : env_(env)
33 {
34     AUDIO_DEBUG_LOG("NapiAudioSpatializationEnabledChangeCallback: instance create");
35 }
36 
~NapiAudioSpatializationEnabledChangeCallback()37 NapiAudioSpatializationEnabledChangeCallback::~NapiAudioSpatializationEnabledChangeCallback()
38 {
39     AUDIO_DEBUG_LOG("NapiAudioSpatializationEnabledChangeCallback: instance destroy");
40 }
41 
SaveSpatializationEnabledChangeCallbackReference(napi_value args,const std::string & cbName)42 void NapiAudioSpatializationEnabledChangeCallback::SaveSpatializationEnabledChangeCallbackReference(napi_value args,
43     const std::string &cbName)
44 {
45     std::lock_guard<std::mutex> lock(mutex_);
46     napi_ref callback = nullptr;
47     const int32_t refCount = ARGS_ONE;
48 
49     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
50         for (auto it = spatializationEnabledChangeCbList_.begin();
51             it != spatializationEnabledChangeCbList_.end(); ++it) {
52             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
53             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
54         }
55 
56         napi_status status = napi_create_reference(env_, args, refCount, &callback);
57         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
58             "NapiAudioSpatializationEnabledChangeCallback: creating reference for callback fail");
59 
60         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
61         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioSpatializationEnabledChangeCallback: creating callback failed");
62         spatializationEnabledChangeCbList_.push_back(cb);
63     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
64         for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
65             it != spatializationEnabledChangeCbForAnyDeviceList_.end(); ++it) {
66             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
67             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
68         }
69 
70         napi_status status = napi_create_reference(env_, args, refCount, &callback);
71         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
72             "NapiAudioSpatializationEnabledChangeCallback: creating reference for callback fail");
73 
74         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
75         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioSpatializationEnabledChangeCallback: creating callback failed");
76         spatializationEnabledChangeCbForAnyDeviceList_.push_back(cb);
77     }
78 }
79 
RemoveSpatializationEnabledChangeCallbackReference(napi_env env,napi_value args,const std::string & cbName)80 void NapiAudioSpatializationEnabledChangeCallback::RemoveSpatializationEnabledChangeCallbackReference(napi_env env,
81     napi_value args, const std::string &cbName)
82 {
83     std::lock_guard<std::mutex> lock(mutex_);
84     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
85         for (auto it = spatializationEnabledChangeCbList_.begin();
86             it != spatializationEnabledChangeCbList_.end(); ++it) {
87             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
88             if (isSameCallback) {
89                 AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: find js callback, delete it");
90                 napi_delete_reference(env, (*it)->cb_);
91                 (*it)->cb_ = nullptr;
92                 spatializationEnabledChangeCbList_.erase(it);
93                 return;
94             }
95         }
96     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
97         for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
98             it != spatializationEnabledChangeCbForAnyDeviceList_.end(); ++it) {
99             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
100             if (isSameCallback) {
101                 AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: find js callback, delete it");
102                 napi_delete_reference(env, (*it)->cb_);
103                 (*it)->cb_ = nullptr;
104                 spatializationEnabledChangeCbForAnyDeviceList_.erase(it);
105                 return;
106             }
107         }
108     }
109     AUDIO_INFO_LOG("RemoveSpatializationEnabledChangeCallbackReference: js callback no find");
110 }
111 
RemoveAllSpatializationEnabledChangeCallbackReference(const std::string & cbName)112 void NapiAudioSpatializationEnabledChangeCallback::RemoveAllSpatializationEnabledChangeCallbackReference(
113     const std::string &cbName)
114 {
115     std::lock_guard<std::mutex> lock(mutex_);
116     if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) {
117         for (auto it = spatializationEnabledChangeCbList_.begin();
118             it != spatializationEnabledChangeCbList_.end(); ++it) {
119             napi_delete_reference(env_, (*it)->cb_);
120             (*it)->cb_ = nullptr;
121         }
122         spatializationEnabledChangeCbList_.clear();
123     } else if (!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
124         for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
125             it != spatializationEnabledChangeCbForAnyDeviceList_.end(); ++it) {
126             napi_delete_reference(env_, (*it)->cb_);
127             (*it)->cb_ = nullptr;
128         }
129         spatializationEnabledChangeCbForAnyDeviceList_.clear();
130     }
131     AUDIO_INFO_LOG("RemoveAllSpatializationEnabledChangeCallbackReference: remove all js callbacks success");
132 }
133 
GetSpatializationEnabledChangeCbListSize(const std::string & cbName)134 int32_t NapiAudioSpatializationEnabledChangeCallback::GetSpatializationEnabledChangeCbListSize(
135     const std::string &cbName)
136 {
137     std::lock_guard<std::mutex> lock(mutex_);
138     return ((!cbName.compare(SPATIALIZATION_ENABLED_CHANGE_CALLBACK_NAME)) ? spatializationEnabledChangeCbList_.size():
139         spatializationEnabledChangeCbForAnyDeviceList_.size());
140 }
141 
OnSpatializationEnabledChange(const bool & enabled)142 void NapiAudioSpatializationEnabledChangeCallback::OnSpatializationEnabledChange(const bool &enabled)
143 {
144     AUDIO_INFO_LOG("OnSpatializationEnabledChange entered");
145     std::lock_guard<std::mutex> lock(mutex_);
146 
147     for (auto it = spatializationEnabledChangeCbList_.begin(); it != spatializationEnabledChangeCbList_.end(); it++) {
148         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
149             std::make_unique<AudioSpatializationEnabledJsCallback>();
150         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
151         cb->callback = (*it);
152         cb->enabled = enabled;
153         onSpatializationEnabledChangeFlag_ = true;
154         OnJsCallbackSpatializationEnabled(cb);
155     }
156     return;
157 }
158 
OnSpatializationEnabledChangeForAnyDevice(const sptr<AudioDeviceDescriptor> & deviceDescriptor,const bool & enabled)159 void NapiAudioSpatializationEnabledChangeCallback::OnSpatializationEnabledChangeForAnyDevice(
160     const sptr<AudioDeviceDescriptor> &deviceDescriptor, const bool &enabled)
161 {
162     AUDIO_INFO_LOG("OnSpatializationEnabledChange by the speified device entered");
163     std::lock_guard<std::mutex> lock(mutex_);
164 
165     for (auto it = spatializationEnabledChangeCbList_.begin(); it != spatializationEnabledChangeCbList_.end(); it++) {
166         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
167             std::make_unique<AudioSpatializationEnabledJsCallback>();
168         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
169         cb->callback = (*it);
170         cb->enabled = enabled;
171         onSpatializationEnabledChangeFlag_ = true;
172         OnJsCallbackSpatializationEnabled(cb);
173     }
174     for (auto it = spatializationEnabledChangeCbForAnyDeviceList_.begin();
175         it != spatializationEnabledChangeCbForAnyDeviceList_.end(); it++) {
176         std::unique_ptr<AudioSpatializationEnabledJsCallback> cb =
177             std::make_unique<AudioSpatializationEnabledJsCallback>();
178         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
179         cb->callback = (*it);
180         cb->deviceDescriptor = deviceDescriptor;
181         cb->enabled = enabled;
182         onSpatializationEnabledChangeFlag_ = false;
183         OnJsCallbackSpatializationEnabled(cb);
184     }
185 
186     return;
187 }
188 
WorkCallbackInterruptDone(uv_work_t * work,int status)189 void NapiAudioSpatializationEnabledChangeCallback::WorkCallbackInterruptDone(uv_work_t *work, int status)
190 {
191     std::shared_ptr<AudioSpatializationEnabledJsCallback> context(
192         static_cast<AudioSpatializationEnabledJsCallback*>(work->data),
193         [work](AudioSpatializationEnabledJsCallback* ptr) {
194             delete ptr;
195             delete work;
196     });
197     CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
198     AudioSpatializationEnabledJsCallback *event = reinterpret_cast<AudioSpatializationEnabledJsCallback *>(work->data);
199     CHECK_AND_RETURN_LOG(event != nullptr, "event is nullptr");
200     CHECK_AND_RETURN_LOG(event->callback != nullptr, "event is nullptr");
201     napi_env env = event->callback->env_;
202     napi_ref callback = event->callback->cb_;
203     napi_handle_scope scope = nullptr;
204     napi_open_handle_scope(env, &scope);
205     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
206     do {
207         napi_value jsCallback = nullptr;
208         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
209         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "callback get reference value fail");
210         napi_value args[ARGS_ONE] = { nullptr };
211         const size_t argCount = ARGS_ONE;
212         napi_value result = nullptr;
213 
214         if (onSpatializationEnabledChangeFlag_) {
215             NapiParamUtils::SetValueBoolean(env, event->enabled, args[PARAM0]);
216             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
217         } else {
218             AudioSpatialEnabledStateForDevice audioSpatialEnabledStateForDevice;
219             audioSpatialEnabledStateForDevice.deviceDescriptor = event->deviceDescriptor;
220             audioSpatialEnabledStateForDevice.enabled = event->enabled;
221             NapiParamUtils::SetAudioSpatialEnabledStateForDevice(env, audioSpatialEnabledStateForDevice, args[PARAM0]);
222             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
223         }
224 
225         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
226         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call spatialization enabled callback");
227     } while (0);
228     napi_close_handle_scope(env, scope);
229 }
230 
OnJsCallbackSpatializationEnabled(std::unique_ptr<AudioSpatializationEnabledJsCallback> & jsCb)231 void NapiAudioSpatializationEnabledChangeCallback::OnJsCallbackSpatializationEnabled(
232     std::unique_ptr<AudioSpatializationEnabledJsCallback> &jsCb)
233 {
234     uv_loop_s *loop = nullptr;
235     napi_get_uv_event_loop(env_, &loop);
236     CHECK_AND_RETURN_LOG(loop != nullptr, "loop is nullptr");
237 
238     uv_work_t *work = new(std::nothrow) uv_work_t;
239     CHECK_AND_RETURN_LOG(work != nullptr, "OnJsCallbackSpatializationEnabled: No memory");
240 
241     work->data = reinterpret_cast<void *>(jsCb.get());
242     int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, WorkCallbackInterruptDone,
243         uv_qos_default);
244     if (ret != 0) {
245         AUDIO_ERR_LOG("Failed to execute libuv work queue");
246         delete work;
247     } else {
248         jsCb.release();
249     }
250 }
251 
NapiAudioHeadTrackingEnabledChangeCallback(napi_env env)252 NapiAudioHeadTrackingEnabledChangeCallback::NapiAudioHeadTrackingEnabledChangeCallback(napi_env env)
253     : env_(env)
254 {
255     AUDIO_DEBUG_LOG("NapiAudioHeadTrackingEnabledChangeCallback: instance create");
256 }
257 
~NapiAudioHeadTrackingEnabledChangeCallback()258 NapiAudioHeadTrackingEnabledChangeCallback::~NapiAudioHeadTrackingEnabledChangeCallback()
259 {
260     AUDIO_DEBUG_LOG("NapiAudioHeadTrackingEnabledChangeCallback: instance destroy");
261 }
262 
SaveHeadTrackingEnabledChangeCallbackReference(napi_value args,const std::string & cbName)263 void NapiAudioHeadTrackingEnabledChangeCallback::SaveHeadTrackingEnabledChangeCallbackReference(napi_value args,
264     const std::string &cbName)
265 {
266     std::lock_guard<std::mutex> lock(mutex_);
267     napi_ref callback = nullptr;
268     const int32_t refCount = ARGS_ONE;
269     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
270         for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); ++it) {
271             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
272             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
273         }
274 
275         napi_status status = napi_create_reference(env_, args, refCount, &callback);
276         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
277             "NapiAudioHeadTrackingEnabledChangeCallback: creating reference for callback fail");
278 
279         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
280         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioHeadTrackingEnabledChangeCallback: creating callback failed");
281 
282         headTrackingEnabledChangeCbList_.push_back(cb);
283     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
284         for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
285             it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); ++it) {
286             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
287             CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: spatialization manager has same callback");
288         }
289 
290         napi_status status = napi_create_reference(env_, args, refCount, &callback);
291         CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
292             "NapiAudioHeadTrackingEnabledChangeCallback: creating reference for callback fail");
293 
294         std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
295         CHECK_AND_RETURN_LOG(cb != nullptr, "NapiAudioHeadTrackingEnabledChangeCallback: creating callback failed");
296 
297         headTrackingEnabledChangeCbForAnyDeviceList_.push_back(cb);
298     }
299 }
300 
RemoveHeadTrackingEnabledChangeCallbackReference(napi_env env,napi_value args,const std::string & cbName)301 void NapiAudioHeadTrackingEnabledChangeCallback::RemoveHeadTrackingEnabledChangeCallbackReference(napi_env env,
302     napi_value args, const std::string &cbName)
303 {
304     std::lock_guard<std::mutex> lock(mutex_);
305     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
306         for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); ++it) {
307             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
308             if (isSameCallback) {
309                 AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: find js callback, delete it");
310                 napi_delete_reference(env, (*it)->cb_);
311                 (*it)->cb_ = nullptr;
312                 headTrackingEnabledChangeCbList_.erase(it);
313                 return;
314             }
315         }
316     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
317         for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
318             it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); ++it) {
319             bool isSameCallback = NapiAudioManagerCallback::IsSameCallback(env_, args, (*it)->cb_);
320             if (isSameCallback) {
321                 AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: find js callback, delete it");
322                 napi_delete_reference(env, (*it)->cb_);
323                 (*it)->cb_ = nullptr;
324                 headTrackingEnabledChangeCbForAnyDeviceList_.erase(it);
325                 return;
326             }
327         }
328     }
329     AUDIO_INFO_LOG("RemoveHeadTrackingEnabledChangeCallbackReference: js callback no find");
330 }
331 
RemoveAllHeadTrackingEnabledChangeCallbackReference(const std::string & cbName)332 void NapiAudioHeadTrackingEnabledChangeCallback::RemoveAllHeadTrackingEnabledChangeCallbackReference(const std::string
333     &cbName)
334 {
335     std::lock_guard<std::mutex> lock(mutex_);
336     if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) {
337         for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); ++it) {
338             napi_delete_reference(env_, (*it)->cb_);
339             (*it)->cb_ = nullptr;
340         }
341         headTrackingEnabledChangeCbList_.clear();
342     } else if (!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_FOR_ANY_DEVICES_CALLBACK_NAME)) {
343         for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
344             it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); ++it) {
345             napi_delete_reference(env_, (*it)->cb_);
346             (*it)->cb_ = nullptr;
347         }
348         headTrackingEnabledChangeCbForAnyDeviceList_.clear();
349     }
350     AUDIO_INFO_LOG("RemoveAllHeadTrackingEnabledChangeCallbackReference: remove all js callbacks success");
351 }
352 
GetHeadTrackingEnabledChangeCbListSize(const std::string & cbName)353 int32_t NapiAudioHeadTrackingEnabledChangeCallback::GetHeadTrackingEnabledChangeCbListSize(const std::string &cbName)
354 {
355     std::lock_guard<std::mutex> lock(mutex_);
356     return ((!cbName.compare(HEAD_TRACKING_ENABLED_CHANGE_CALLBACK_NAME)) ? headTrackingEnabledChangeCbList_.size():
357         headTrackingEnabledChangeCbForAnyDeviceList_.size());
358 }
359 
OnHeadTrackingEnabledChange(const bool & enabled)360 void NapiAudioHeadTrackingEnabledChangeCallback::OnHeadTrackingEnabledChange(const bool &enabled)
361 {
362     AUDIO_INFO_LOG("OnHeadTrackingEnabledChange entered");
363     std::lock_guard<std::mutex> lock(mutex_);
364 
365     for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); it++) {
366         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
367             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
368         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
369         cb->callback = (*it);
370         cb->enabled = enabled;
371         onHeadTrackingEnabledChangeFlag_ = true;
372         OnJsCallbackHeadTrackingEnabled(cb);
373     }
374 
375     return;
376 }
377 
OnHeadTrackingEnabledChangeForAnyDevice(const sptr<AudioDeviceDescriptor> & deviceDescriptor,const bool & enabled)378 void NapiAudioHeadTrackingEnabledChangeCallback::OnHeadTrackingEnabledChangeForAnyDevice(
379     const sptr<AudioDeviceDescriptor> &deviceDescriptor, const bool &enabled)
380 {
381     AUDIO_INFO_LOG("OnHeadTrackingEnabledChange by the specified device entered");
382     std::lock_guard<std::mutex> lock(mutex_);
383 
384     for (auto it = headTrackingEnabledChangeCbList_.begin(); it != headTrackingEnabledChangeCbList_.end(); it++) {
385         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
386             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
387         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
388         cb->callback = (*it);
389         cb->enabled = enabled;
390         onHeadTrackingEnabledChangeFlag_ = true;
391         OnJsCallbackHeadTrackingEnabled(cb);
392     }
393     for (auto it = headTrackingEnabledChangeCbForAnyDeviceList_.begin();
394         it != headTrackingEnabledChangeCbForAnyDeviceList_.end(); it++) {
395         std::unique_ptr<AudioHeadTrackingEnabledJsCallback> cb =
396             std::make_unique<AudioHeadTrackingEnabledJsCallback>();
397         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory!!");
398         cb->callback = (*it);
399         cb->deviceDescriptor = deviceDescriptor;
400         cb->enabled = enabled;
401         onHeadTrackingEnabledChangeFlag_ = false;
402         OnJsCallbackHeadTrackingEnabled(cb);
403     }
404 
405     return;
406 }
407 
WorkCallbackInterruptDone(uv_work_t * work,int status)408 void NapiAudioHeadTrackingEnabledChangeCallback::WorkCallbackInterruptDone(uv_work_t *work, int status)
409 {
410     std::shared_ptr<AudioHeadTrackingEnabledJsCallback> context(
411         static_cast<AudioHeadTrackingEnabledJsCallback*>(work->data),
412         [work](AudioHeadTrackingEnabledJsCallback* ptr) {
413             delete ptr;
414             delete work;
415     });
416     CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
417     AudioHeadTrackingEnabledJsCallback *event = reinterpret_cast<AudioHeadTrackingEnabledJsCallback *>(work->data);
418     CHECK_AND_RETURN_LOG(event != nullptr, "event is nullptr");
419     CHECK_AND_RETURN_LOG(event->callback != nullptr, "event is nullptr");
420     napi_env env = event->callback->env_;
421     napi_ref callback = event->callback->cb_;
422     napi_handle_scope scope = nullptr;
423     napi_open_handle_scope(env, &scope);
424     CHECK_AND_RETURN_LOG(scope != nullptr, "scope is nullptr");
425     do {
426         napi_value jsCallback = nullptr;
427         napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
428         CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "callback get reference value fail");
429         napi_value args[ARGS_ONE] = { nullptr };
430         const size_t argCount = ARGS_ONE;
431         napi_value result = nullptr;
432 
433         if (onHeadTrackingEnabledChangeFlag_) {
434             NapiParamUtils::SetValueBoolean(env, event->enabled, args[PARAM0]);
435             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
436         } else {
437             AudioSpatialEnabledStateForDevice audioSpatialEnabledStateForDevice;
438             audioSpatialEnabledStateForDevice.deviceDescriptor = event->deviceDescriptor;
439             audioSpatialEnabledStateForDevice.enabled = event->enabled;
440             NapiParamUtils::SetAudioSpatialEnabledStateForDevice(env, audioSpatialEnabledStateForDevice, args[PARAM0]);
441             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[PARAM0] != nullptr, "fail to convert to jsobj");
442         }
443 
444         nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
445         CHECK_AND_BREAK_LOG(nstatus == napi_ok, "Fail to call head tracking enabled callback");
446     } while (0);
447     napi_close_handle_scope(env, scope);
448 }
449 
OnJsCallbackHeadTrackingEnabled(std::unique_ptr<AudioHeadTrackingEnabledJsCallback> & jsCb)450 void NapiAudioHeadTrackingEnabledChangeCallback::OnJsCallbackHeadTrackingEnabled(
451     std::unique_ptr<AudioHeadTrackingEnabledJsCallback> &jsCb)
452 {
453     uv_loop_s *loop = nullptr;
454     napi_get_uv_event_loop(env_, &loop);
455     CHECK_AND_RETURN_LOG(loop != nullptr, "loop is nullptr");
456 
457     uv_work_t *work = new(std::nothrow) uv_work_t;
458     CHECK_AND_RETURN_LOG(work != nullptr, "OnJsCallbackHeadTrackingEnabled: No memory");
459 
460     work->data = reinterpret_cast<void *>(jsCb.get());
461     int ret = uv_queue_work_with_qos(loop, work, [] (uv_work_t *work) {}, WorkCallbackInterruptDone,
462         uv_qos_default);
463     if (ret != 0) {
464         AUDIO_ERR_LOG("Failed to execute libuv work queue");
465         delete work;
466     } else {
467         jsCb.release();
468     }
469 }
470 } // namespace AudioStandard
471 } // namespace OHOS