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
16 #include "recorder_callback_napi.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "media_log.h"
20
21 namespace {
22 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "RecorderCallbackNapi"};
23 }
24
25 namespace OHOS {
26 namespace Media {
RecorderCallbackNapi(napi_env env,bool isVideo)27 RecorderCallbackNapi::RecorderCallbackNapi(napi_env env, bool isVideo)
28 : env_(env), isVideo_(isVideo)
29 {
30 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
31 }
32
~RecorderCallbackNapi()33 RecorderCallbackNapi::~RecorderCallbackNapi()
34 {
35 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
36 }
37
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)38 void RecorderCallbackNapi::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
39 {
40 std::lock_guard<std::mutex> lock(mutex_);
41 refMap_[name] = ref;
42 }
43
ClearCallbackReference()44 void RecorderCallbackNapi::ClearCallbackReference()
45 {
46 std::lock_guard<std::mutex> lock(mutex_);
47 refMap_.clear();
48 }
49
SendErrorCallback(int32_t errCode)50 void RecorderCallbackNapi::SendErrorCallback(int32_t errCode)
51 {
52 std::lock_guard<std::mutex> lock(mutex_);
53 if (refMap_.find(ERROR_CALLBACK_NAME) == refMap_.end()) {
54 MEDIA_LOGW("can not find error callback!");
55 return;
56 }
57
58 RecordJsCallback *cb = new(std::nothrow) RecordJsCallback();
59 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
60 cb->autoRef = refMap_.at(ERROR_CALLBACK_NAME);
61 cb->callbackName = ERROR_CALLBACK_NAME;
62 if (isVideo_) {
63 cb->errorMsg = MSExtErrorAPI9ToString(static_cast<MediaServiceExtErrCodeAPI9>(errCode), "", "");
64 } else {
65 cb->errorMsg = MSExtErrorToString(static_cast<MediaServiceExtErrCode>(errCode));
66 }
67 cb->errorCode = errCode;
68 return OnJsErrorCallBack(cb);
69 }
70
SendStateCallback(const std::string & callbackName)71 void RecorderCallbackNapi::SendStateCallback(const std::string &callbackName)
72 {
73 std::lock_guard<std::mutex> lock(mutex_);
74 if (refMap_.find(callbackName) == refMap_.end()) {
75 MEDIA_LOGW("can not find %{public}s callback!", callbackName.c_str());
76 return;
77 }
78
79 RecordJsCallback *cb = new(std::nothrow) RecordJsCallback();
80 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
81 cb->autoRef = refMap_.at(callbackName);
82 cb->callbackName = callbackName;
83 return OnJsStateCallBack(cb);
84 }
85
OnError(RecorderErrorType errorType,int32_t errCode)86 void RecorderCallbackNapi::OnError(RecorderErrorType errorType, int32_t errCode)
87 {
88 MEDIA_LOGD("OnError is called, name: %{public}d, error message: %{public}d", errorType, errCode);
89 if (isVideo_) {
90 MediaServiceExtErrCode err = MSErrorToExtError(static_cast<MediaServiceErrCode>(errCode));
91 return SendErrorCallback(err);
92 } else {
93 MediaServiceExtErrCodeAPI9 err = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errCode));
94 return SendErrorCallback(err);
95 }
96 }
97
OnInfo(int32_t type,int32_t extra)98 void RecorderCallbackNapi::OnInfo(int32_t type, int32_t extra)
99 {
100 MEDIA_LOGD("OnInfo() is called, type: %{public}d, extra: %{public}d", type, extra);
101 }
102
OnJsStateCallBack(RecordJsCallback * jsCb) const103 void RecorderCallbackNapi::OnJsStateCallBack(RecordJsCallback *jsCb) const
104 {
105 uv_loop_s *loop = nullptr;
106 napi_get_uv_event_loop(env_, &loop);
107 if (loop == nullptr) {
108 MEDIA_LOGE("fail to get uv event loop");
109 delete jsCb;
110 return;
111 }
112
113 uv_work_t *work = new(std::nothrow) uv_work_t;
114 if (work == nullptr) {
115 MEDIA_LOGE("fail to new uv_work_t");
116 delete jsCb;
117 return;
118 }
119
120 work->data = reinterpret_cast<void *>(jsCb);
121 int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
122 // Js Thread
123 CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
124 RecordJsCallback *event = reinterpret_cast<RecordJsCallback *>(work->data);
125 std::string request = event->callbackName;
126 MEDIA_LOGD("OnJsStateCallBack %{public}s, uv_queue_work start", request.c_str());
127 do {
128 CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
129 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
130 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
131
132 napi_value jsCallback = nullptr;
133 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
134 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
135 request.c_str());
136
137 napi_value result = nullptr;
138 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 0, nullptr, &result);
139 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
140 } while (0);
141 delete event;
142 delete work;
143 });
144 if (ret != 0) {
145 MEDIA_LOGE("fail to uv_queue_work task");
146 delete jsCb;
147 delete work;
148 }
149 }
150
OnJsErrorCallBack(RecordJsCallback * jsCb) const151 void RecorderCallbackNapi::OnJsErrorCallBack(RecordJsCallback *jsCb) const
152 {
153 uv_loop_s *loop = nullptr;
154 napi_get_uv_event_loop(env_, &loop);
155
156 uv_work_t *work = new(std::nothrow) uv_work_t;
157 if (work == nullptr) {
158 MEDIA_LOGE("No memory");
159 delete jsCb;
160 return;
161 }
162 work->data = reinterpret_cast<void *>(jsCb);
163
164 // async callback, jsWork and jsWork->data should be heap object.
165 int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
166 // Js Thread
167 CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
168 RecordJsCallback *event = reinterpret_cast<RecordJsCallback *>(work->data);
169 std::string request = event->callbackName;
170 MEDIA_LOGD("JsCallBack %{public}s, uv_queue_work start", request.c_str());
171 do {
172 CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
173 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
174 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
175
176 napi_value jsCallback = nullptr;
177 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
178 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
179 request.c_str());
180
181 napi_value msgValStr = nullptr;
182 nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
183 CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "%{public}s fail to get error code value",
184 request.c_str());
185
186 napi_value args[1] = { nullptr };
187 nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
188 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "%{public}s fail to create error callback",
189 request.c_str());
190
191 nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
192 CHECK_AND_RETURN_LOG(nstatus == napi_ok, "create error callback fail");
193
194 // Call back function
195 napi_value result = nullptr;
196 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
197 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
198 } while (0);
199 delete event;
200 delete work;
201 });
202 if (ret != 0) {
203 MEDIA_LOGE("Failed to execute libuv work queue");
204 delete jsCb;
205 delete work;
206 }
207 }
208 } // namespace Media
209 } // namespace OHOS
210