• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "soundpool_callback_napi.h"
16 #include <uv.h>
17 #include "media_errors.h"
18 #include "media_log.h"
19 #include "scope_guard.h"
20 
21 namespace {
22     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "SoundPoolCallBackNapi"};
23 }
24 
25 namespace OHOS {
26 namespace Media {
SoundPoolCallBackNapi(napi_env env)27 SoundPoolCallBackNapi::SoundPoolCallBackNapi(napi_env env)
28 {
29     env_ = env;
30     MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
31 }
32 
OnLoadCompleted(int32_t soundId)33 void SoundPoolCallBackNapi::OnLoadCompleted(int32_t soundId)
34 {
35     MEDIA_LOGI("OnLoadCompleted recived soundId:%{public}d", soundId);
36     SendLoadCompletedCallback(soundId);
37 }
38 
OnPlayFinished()39 void SoundPoolCallBackNapi::OnPlayFinished()
40 {
41     MEDIA_LOGI("OnPlayFinished recived");
42     SendPlayCompletedCallback();
43 }
44 
OnError(int32_t errorCode)45 void SoundPoolCallBackNapi::OnError(int32_t errorCode)
46 {
47     MEDIA_LOGI("OnError recived:error:%{public}d", errorCode);
48     if (errorCode == MSERR_INVALID_OPERATION) {
49         SendErrorCallback(MSERR_EXT_API9_OPERATE_NOT_PERMIT,
50             "The soundpool timed out. Please confirm that the input stream is normal.");
51     } else if (errorCode == MSERR_NO_MEMORY) {
52         SendErrorCallback(MSERR_EXT_API9_NO_MEMORY, "soundpool memery error.");
53     } else if (errorCode == MSERR_SERVICE_DIED) {
54         SendErrorCallback(MSERR_EXT_API9_SERVICE_DIED, "releated server died");
55     } else {
56         SendErrorCallback(MSERR_EXT_API9_IO, "IO error happened.");
57     }
58 }
59 
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)60 void SoundPoolCallBackNapi::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
61 {
62     std::lock_guard<std::mutex> lock(mutex_);
63     refMap_[name] = ref;
64     MEDIA_LOGI("Set callback type: %{public}s", name.c_str());
65 }
66 
CancelCallbackReference(const std::string & name)67 void SoundPoolCallBackNapi::CancelCallbackReference(const std::string &name)
68 {
69     std::lock_guard<std::mutex> lock(mutex_);
70     auto iter = refMap_.find(name);
71     if (iter != refMap_.end()) {
72         refMap_.erase(iter);
73     }
74     MEDIA_LOGI("Cancel callback type: %{public}s", name.c_str());
75 }
76 
ClearCallbackReference()77 void SoundPoolCallBackNapi::ClearCallbackReference()
78 {
79     std::lock_guard<std::mutex> lock(mutex_);
80     refMap_.clear();
81     MEDIA_LOGI("ClearCallback!");
82 }
83 
SendErrorCallback(int32_t errCode,const std::string & msg)84 void SoundPoolCallBackNapi::SendErrorCallback(int32_t errCode, const std::string &msg)
85 {
86     std::lock_guard<std::mutex> lock(mutex_);
87     if (refMap_.find(SoundPoolEvent::EVENT_ERROR) == refMap_.end()) {
88         MEDIA_LOGW("can not find error callback!");
89         return;
90     }
91 
92     SoundPoolJsCallBack *cb = new(std::nothrow) SoundPoolJsCallBack();
93     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
94     cb->autoRef = refMap_.at(SoundPoolEvent::EVENT_ERROR);
95     cb->callbackName = SoundPoolEvent::EVENT_ERROR;
96     cb->errorCode = errCode;
97     cb->errorMsg = msg;
98     return OnJsErrorCallBack(cb);
99 }
100 
SendLoadCompletedCallback(int32_t soundId)101 void SoundPoolCallBackNapi::SendLoadCompletedCallback(int32_t soundId)
102 {
103     std::lock_guard<std::mutex> lock(mutex_);
104     if (refMap_.find(SoundPoolEvent::EVENT_LOAD_COMPLETED) == refMap_.end()) {
105         MEDIA_LOGW("can not find loadcompleted callback!");
106         return;
107     }
108 
109     SoundPoolJsCallBack *cb = new(std::nothrow) SoundPoolJsCallBack();
110     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
111     cb->autoRef = refMap_.at(SoundPoolEvent::EVENT_LOAD_COMPLETED);
112     cb->callbackName = SoundPoolEvent::EVENT_LOAD_COMPLETED;
113     cb->loadSoundId = soundId;
114     return OnJsloadCompletedCallBack(cb);
115 }
116 
SendPlayCompletedCallback()117 void SoundPoolCallBackNapi::SendPlayCompletedCallback()
118 {
119     std::lock_guard<std::mutex> lock(mutex_);
120     if (refMap_.find(SoundPoolEvent::EVENT_PLAY_FINISHED) == refMap_.end()) {
121         MEDIA_LOGW("can not find playfinished callback!");
122         return;
123     }
124 
125     SoundPoolJsCallBack *cb = new(std::nothrow) SoundPoolJsCallBack();
126     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
127     cb->autoRef = refMap_.at(SoundPoolEvent::EVENT_PLAY_FINISHED);
128     cb->callbackName = SoundPoolEvent::EVENT_PLAY_FINISHED;
129     return OnJsplayCompletedCallBack(cb);
130 }
131 
OnJsErrorCallBack(SoundPoolJsCallBack * jsCb) const132 void SoundPoolCallBackNapi::OnJsErrorCallBack(SoundPoolJsCallBack *jsCb) const
133 {
134     ON_SCOPE_EXIT(0) {
135         delete jsCb;
136     };
137     uv_loop_s *loop = nullptr;
138     napi_get_uv_event_loop(env_, &loop);
139     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
140 
141     uv_work_t *work = new(std::nothrow) uv_work_t;
142     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
143     ON_SCOPE_EXIT(1) {
144         delete work;
145     };
146     work->data = reinterpret_cast<void *>(jsCb);
147     // async callback, jsWork and jsWork->data should be heap object.
148     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
149         // Js Thread
150         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
151         CHECK_AND_RETURN_LOG(work->data != nullptr, "workdata is nullptr");
152         SoundPoolJsCallBack *event = reinterpret_cast<SoundPoolJsCallBack *>(work->data);
153         std::string request = event->callbackName;
154         do {
155             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
156             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
157             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
158 
159             napi_handle_scope scope = nullptr;
160             napi_open_handle_scope(ref->env_, &scope);
161             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
162             ON_SCOPE_EXIT(0) {
163                 napi_close_handle_scope(ref->env_, scope);
164             };
165             napi_value jsCallback = nullptr;
166             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
167             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
168                 request.c_str());
169             napi_value msgValStr = nullptr;
170             nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
171             CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
172 
173             napi_value args[1] = { nullptr };
174             nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
175             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
176             nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
177             CHECK_AND_RETURN_LOG(nstatus == napi_ok, "create error callback fail");
178             // Call back function
179             napi_value result = nullptr;
180             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
181             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
182         } while (0);
183         delete event;
184         delete work;
185     });
186     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
187     CANCEL_SCOPE_EXIT_GUARD(0);
188     CANCEL_SCOPE_EXIT_GUARD(1);
189 }
190 
OnJsloadCompletedCallBack(SoundPoolJsCallBack * jsCb) const191 void SoundPoolCallBackNapi::OnJsloadCompletedCallBack(SoundPoolJsCallBack *jsCb) const
192 {
193     ON_SCOPE_EXIT(0) {
194         delete jsCb;
195     };
196     uv_loop_s *loop = nullptr;
197     napi_get_uv_event_loop(env_, &loop);
198     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
199 
200     uv_work_t *work = new(std::nothrow) uv_work_t;
201     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
202     ON_SCOPE_EXIT(1) {
203         delete work;
204     };
205     work->data = reinterpret_cast<void *>(jsCb);
206     // async callback, jsWork and jsWork->data should be heap object.
207     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
208         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
209         CHECK_AND_RETURN_LOG(work->data != nullptr, "workdata is nullptr");
210         SoundPoolJsCallBack *event = reinterpret_cast<SoundPoolJsCallBack *>(work->data);
211         std::string request = event->callbackName;
212         do {
213             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
214             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
215             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
216             napi_handle_scope scope = nullptr;
217             napi_open_handle_scope(ref->env_, &scope);
218             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
219             ON_SCOPE_EXIT(0) {
220                 napi_close_handle_scope(ref->env_, scope);
221             };
222             napi_value jsCallback = nullptr;
223             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
224             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
225                 request.c_str());
226             napi_value args[1] = { nullptr };
227             nstatus = napi_create_int32(ref->env_, event->loadSoundId, &args[0]);
228             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
229                 "%{public}s fail to create callback", request.c_str());
230             const size_t argCount = 1;
231             napi_value result = nullptr;
232             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
233             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
234         } while (0);
235         delete event;
236         delete work;
237     });
238     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
239     CANCEL_SCOPE_EXIT_GUARD(0);
240     CANCEL_SCOPE_EXIT_GUARD(1);
241 }
242 
OnJsplayCompletedCallBack(SoundPoolJsCallBack * jsCb) const243 void SoundPoolCallBackNapi::OnJsplayCompletedCallBack(SoundPoolJsCallBack *jsCb) const
244 {
245     ON_SCOPE_EXIT(0) {
246         delete jsCb;
247     };
248     uv_loop_s *loop = nullptr;
249     napi_get_uv_event_loop(env_, &loop);
250     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
251 
252     uv_work_t *work = new(std::nothrow) uv_work_t;
253     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
254     ON_SCOPE_EXIT(1) {
255         delete work;
256     };
257     work->data = reinterpret_cast<void *>(jsCb);
258     // async callback, jsWork and jsWork->data should be heap object.
259     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
260         // Js Thread
261         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
262         CHECK_AND_RETURN_LOG(work->data != nullptr, "workdata is nullptr");
263         SoundPoolJsCallBack *event = reinterpret_cast<SoundPoolJsCallBack *>(work->data);
264         std::string request = event->callbackName;
265         do {
266             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
267             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
268             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
269 
270             napi_handle_scope scope = nullptr;
271             napi_open_handle_scope(ref->env_, &scope);
272             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
273             ON_SCOPE_EXIT(0) {
274                 napi_close_handle_scope(ref->env_, scope);
275             };
276             napi_value jsCallback = nullptr;
277             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
278             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
279                 request.c_str());
280 
281             napi_value result = nullptr;
282             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 0, nullptr, &result);
283             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
284         } while (0);
285         delete event;
286         delete work;
287     });
288     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
289 
290     CANCEL_SCOPE_EXIT_GUARD(0);
291     CANCEL_SCOPE_EXIT_GUARD(1);
292 }
293 } // namespace Media
294 } // namespace OHOS