• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include <uv.h>
16 
17 #include "audio_errors.h"
18 #include "audio_log.h"
19 #include "audio_manager_interrupt_callback_napi.h"
20 
21 namespace OHOS {
22 namespace AudioStandard {
AudioManagerInterruptCallbackNapi(napi_env env)23 AudioManagerInterruptCallbackNapi::AudioManagerInterruptCallbackNapi(napi_env env)
24     : env_(env)
25 {
26     AUDIO_INFO_LOG("instance create");
27 }
28 
~AudioManagerInterruptCallbackNapi()29 AudioManagerInterruptCallbackNapi::~AudioManagerInterruptCallbackNapi()
30 {
31     AUDIO_INFO_LOG("instance destroy");
32 }
33 
SaveCallbackReference(const std::string & callbackName,napi_value args)34 void AudioManagerInterruptCallbackNapi::SaveCallbackReference(const std::string &callbackName, napi_value args)
35 {
36     if (callbackName.compare(INTERRUPT_CALLBACK_NAME)) {
37         AUDIO_ERR_LOG("SaveCallbackReference: Unknown callback type: %{public}s", callbackName.c_str());
38         return;
39     }
40 
41     std::lock_guard<std::mutex> lock(mutex_);
42     bool isSameCallback = true;
43     for (auto it = audioManagerInterruptCallbackList_.begin(); it != audioManagerInterruptCallbackList_.end(); ++it) {
44         isSameCallback = AudioCommonNapi::IsSameCallback(env_, args, (*it)->cb_);
45         CHECK_AND_RETURN_LOG(!isSameCallback, "SaveCallbackReference: the callback already exists");
46     }
47     napi_ref callback = nullptr;
48     const int32_t refCount = 1;
49     napi_status status = napi_create_reference(env_, args, refCount, &callback);
50     CHECK_AND_RETURN_LOG(status == napi_ok && callback != nullptr,
51         "SaveCallbackReference: creating reference for callback fail");
52     std::shared_ptr<AutoRef> cb = std::make_shared<AutoRef>(env_, callback);
53     audioManagerInterruptCallbackList_.push_back(cb);
54     AUDIO_INFO_LOG("SaveCallbackReference success, list size [%{public}zu]", audioManagerInterruptCallbackList_.size());
55 }
56 
RemoveCallbackReference(const std::string & callbackName,napi_value args)57 void AudioManagerInterruptCallbackNapi::RemoveCallbackReference(const std::string &callbackName, napi_value args)
58 {
59     if (callbackName.compare(INTERRUPT_CALLBACK_NAME)) {
60         AUDIO_ERR_LOG("RemoveCallbackReference: Unknown callback type: %{public}s", callbackName.c_str());
61         return;
62     }
63 
64     std::lock_guard<std::mutex> lock(mutex_);
65     for (auto it = audioManagerInterruptCallbackList_.begin(); it != audioManagerInterruptCallbackList_.end(); ++it) {
66         bool isSameCallback = AudioCommonNapi::IsSameCallback(env_, args, (*it)->cb_);
67         if (isSameCallback) {
68             napi_status status = napi_delete_reference(env_, (*it)->cb_);
69             (*it)->cb_ = nullptr;
70             CHECK_AND_RETURN_LOG(status == napi_ok, "RemoveCallbackReference: delete reference for callback fail");
71             audioManagerInterruptCallbackList_.erase(it);
72             AUDIO_INFO_LOG("RemoveCallbackReference success, list size [%{public}zu]",
73                 audioManagerInterruptCallbackList_.size());
74             return;
75         }
76     }
77     AUDIO_ERR_LOG("RemoveCallbackReference: js callback no find");
78 }
79 
RemoveAllCallbackReferences(const std::string & callbackName)80 void AudioManagerInterruptCallbackNapi::RemoveAllCallbackReferences(const std::string &callbackName)
81 {
82     if (callbackName.compare(INTERRUPT_CALLBACK_NAME)) {
83         AUDIO_ERR_LOG("RemoveAllCallbackReferences: Unknown callback type: %{public}s", callbackName.c_str());
84         return;
85     }
86     std::lock_guard<std::mutex> lock(mutex_);
87     for (auto it = audioManagerInterruptCallbackList_.begin(); it != audioManagerInterruptCallbackList_.end(); ++it) {
88         napi_status ret = napi_delete_reference(env_, (*it)->cb_);
89         if (ret != napi_ok) {
90             AUDIO_ERR_LOG("RemoveAllCallbackReferences: napi_delete_reference err.");
91         }
92         (*it)->cb_ = nullptr;
93     }
94     audioManagerInterruptCallbackList_.clear();
95     AUDIO_INFO_LOG("RemoveAllCallbackReference: remove all js callbacks success");
96 }
97 
GetInterruptCallbackListSize()98 int32_t AudioManagerInterruptCallbackNapi::GetInterruptCallbackListSize()
99 {
100     std::lock_guard<std::mutex> lock(mutex_);
101     return audioManagerInterruptCallbackList_.size();
102 }
103 
104 
SetValueInt32(const napi_env & env,const std::string & fieldStr,const int intValue,napi_value & result)105 static void SetValueInt32(const napi_env &env, const std::string &fieldStr, const int intValue, napi_value &result)
106 {
107     napi_value value;
108     napi_create_int32(env, intValue, &value);
109     napi_set_named_property(env, result, fieldStr.c_str(), value);
110 }
111 
SetValueBoolean(const napi_env & env,const std::string & fieldStr,const bool boolValue,napi_value & result)112 static void SetValueBoolean(const napi_env &env, const std::string &fieldStr, const bool boolValue, napi_value &result)
113 {
114     napi_value value;
115     napi_get_boolean(env, boolValue, &value);
116     napi_set_named_property(env, result, fieldStr.c_str(), value);
117 }
118 
NativeInterruptActionToJsObj(const napi_env & env,napi_value & jsObj,const InterruptAction & interruptAction)119 static void NativeInterruptActionToJsObj(const napi_env &env, napi_value &jsObj,
120     const InterruptAction &interruptAction)
121 {
122     napi_create_object(env, &jsObj);
123     SetValueInt32(env, "actionType", static_cast<int32_t>(interruptAction.actionType), jsObj);
124     SetValueInt32(env, "type", static_cast<int32_t>(interruptAction.interruptType), jsObj);
125     SetValueInt32(env, "hint", static_cast<int32_t>(interruptAction.interruptHint), jsObj);
126     SetValueBoolean(env, "activated", interruptAction.activated, jsObj);
127 }
128 
OnInterrupt(const InterruptAction & interruptAction)129 void AudioManagerInterruptCallbackNapi::OnInterrupt(const InterruptAction &interruptAction)
130 {
131     std::lock_guard<std::mutex> lock(mutex_);
132     AUDIO_INFO_LOG("OnInterrupt action: %{public}d IntType: %{public}d, IntHint: %{public}d, activated: %{public}d",
133         interruptAction.actionType, interruptAction.interruptType, interruptAction.interruptHint,
134         interruptAction.activated);
135     CHECK_AND_RETURN_LOG(audioManagerInterruptCallbackList_.size() != 0,
136         "Cannot find the reference of interrupt callback");
137     for (auto it = audioManagerInterruptCallbackList_.begin(); it != audioManagerInterruptCallbackList_.end(); ++it) {
138         std::unique_ptr<AudioManagerInterruptJsCallback> cb = std::make_unique<AudioManagerInterruptJsCallback>();
139         CHECK_AND_RETURN_LOG(cb != nullptr, "No memory");
140         cb->callback = *it;
141         cb->callbackName = INTERRUPT_CALLBACK_NAME;
142         cb->interruptAction = interruptAction;
143         OnJsCallbackAudioManagerInterrupt(cb);
144     }
145 }
146 
OnJsCallbackAudioManagerInterrupt(std::unique_ptr<AudioManagerInterruptJsCallback> & jsCb)147 void AudioManagerInterruptCallbackNapi::OnJsCallbackAudioManagerInterrupt (
148     std::unique_ptr<AudioManagerInterruptJsCallback> &jsCb)
149 {
150     uv_loop_s *loop = nullptr;
151     napi_get_uv_event_loop(env_, &loop);
152     if (loop == nullptr) {
153         return;
154     }
155 
156     uv_work_t *work = new(std::nothrow) uv_work_t;
157     if (work == nullptr) {
158         AUDIO_ERR_LOG("OnJsCallbackAudioManagerInterrupt: No memory");
159         return;
160     }
161     if (jsCb.get() == nullptr) {
162         AUDIO_ERR_LOG("OnJsCallbackAudioManagerInterrupt: jsCb.get() is null");
163         delete work;
164         return;
165     }
166     work->data = reinterpret_cast<void *>(jsCb.get());
167 
168     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
169         // Js Thread
170         AudioManagerInterruptJsCallback *event = reinterpret_cast<AudioManagerInterruptJsCallback *>(work->data);
171         std::string request = event->callbackName;
172         napi_env env = event->callback->env_;
173         napi_ref callback = event->callback->cb_;
174         AUDIO_INFO_LOG("OnJsCallbackAudioManagerInterrupt: JsCallBack %{public}s, uv_queue_work start",
175             request.c_str());
176         do {
177             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
178 
179             napi_value jsCallback = nullptr;
180             napi_status nstatus = napi_get_reference_value(env, callback, &jsCallback);
181             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
182                 request.c_str());
183 
184             // Call back function
185             napi_value args[1] = { nullptr };
186             NativeInterruptActionToJsObj(env, args[0], event->interruptAction);
187             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
188                 "%{public}s fail to create Interrupt callback", request.c_str());
189 
190             const size_t argCount = 1;
191             napi_value result = nullptr;
192             nstatus = napi_call_function(env, nullptr, jsCallback, argCount, args, &result);
193             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to call Interrupt callback", request.c_str());
194         } while (0);
195         delete event;
196         delete work;
197     });
198     if (ret != 0) {
199         AUDIO_ERR_LOG("OnJsCallbackAudioManagerInterrupt: Failed to execute libuv work queue");
200         delete work;
201     } else {
202         jsCb.release();
203     }
204 }
205 }  // namespace AudioStandard
206 }  // namespace OHOS
207