1 /*
2 * Copyright (C) 2024 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 "avtranscoder_callback.h"
16 #include <uv.h>
17 #include "media_errors.h"
18 #include "scope_guard.h"
19 #include "media_log.h"
20
21 namespace {
22 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "AVTransCoderCallback"};
23 }
24
25 namespace OHOS {
26 namespace Media {
AVTransCoderCallback(napi_env env)27 AVTransCoderCallback::AVTransCoderCallback(napi_env env) : env_(env)
28 {
29 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
30 }
31
~AVTransCoderCallback()32 AVTransCoderCallback::~AVTransCoderCallback()
33 {
34 MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances destroy", FAKE_POINTER(this));
35 }
36
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)37 void AVTransCoderCallback::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
38 {
39 std::lock_guard<std::mutex> lock(mutex_);
40 refMap_[name] = ref;
41 MEDIA_LOGI("Set callback type: %{public}s", name.c_str());
42 }
43
CancelCallbackReference(const std::string & name)44 void AVTransCoderCallback::CancelCallbackReference(const std::string &name)
45 {
46 std::lock_guard<std::mutex> lock(mutex_);
47 auto iter = refMap_.find(name);
48 if (iter != refMap_.end()) {
49 refMap_.erase(iter);
50 }
51 MEDIA_LOGI("Cancel callback type: %{public}s", name.c_str());
52 }
53
ClearCallbackReference()54 void AVTransCoderCallback::ClearCallbackReference()
55 {
56 std::lock_guard<std::mutex> lock(mutex_);
57 refMap_.clear();
58 MEDIA_LOGI("ClearCallback!");
59 }
60
SendErrorCallback(MediaServiceExtErrCodeAPI9 errCode,const std::string & msg)61 void AVTransCoderCallback::SendErrorCallback(MediaServiceExtErrCodeAPI9 errCode, const std::string &msg)
62 {
63 std::string message = MSExtAVErrorToString(errCode) + msg;
64 MEDIA_LOGE("SendErrorCallback:errorCode %{public}d, errorMsg %{public}s", errCode, message.c_str());
65 std::lock_guard<std::mutex> lock(mutex_);
66 if (refMap_.find(AVTransCoderEvent::EVENT_ERROR) == refMap_.end()) {
67 MEDIA_LOGW("can not find error callback!");
68 return;
69 }
70
71 AVTransCoderJsCallback *cb = new(std::nothrow) AVTransCoderJsCallback();
72 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
73 cb->autoRef = refMap_.at(AVTransCoderEvent::EVENT_ERROR);
74 cb->callbackName = AVTransCoderEvent::EVENT_ERROR;
75 cb->errorCode = errCode;
76 cb->errorMsg = message;
77 return OnJsErrorCallBack(cb);
78 }
79
SendStateCallback(const std::string & state,const StateChangeReason & reason)80 void AVTransCoderCallback::SendStateCallback(const std::string &state, const StateChangeReason &reason)
81 {
82 std::lock_guard<std::mutex> lock(mutex_);
83 MEDIA_LOGI("StateChange, currentState: %{public}s to state: %{public}s", currentState_.c_str(), state.c_str());
84 currentState_ = state;
85 }
86
SendCompleteCallback()87 void AVTransCoderCallback::SendCompleteCallback()
88 {
89 std::lock_guard<std::mutex> lock(mutex_);
90 if (refMap_.find(AVTransCoderEvent::EVENT_COMPLETE) == refMap_.end()) {
91 MEDIA_LOGW("can not find statechange callback!");
92 return;
93 }
94
95 AVTransCoderJsCallback *cb = new(std::nothrow) AVTransCoderJsCallback();
96 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
97 cb->autoRef = refMap_.at(AVTransCoderEvent::EVENT_COMPLETE);
98 cb->callbackName = AVTransCoderEvent::EVENT_COMPLETE;
99 return OnJsCompleteCallBack(cb);
100 }
101
SendProgressUpdateCallback(int32_t progress)102 void AVTransCoderCallback::SendProgressUpdateCallback(int32_t progress)
103 {
104 std::lock_guard<std::mutex> lock(mutex_);
105 if (refMap_.find(AVTransCoderEvent::EVENT_PROGRESS_UPDATE) == refMap_.end()) {
106 MEDIA_LOGW("can not find progressupdate callback!");
107 return;
108 }
109 AVTransCoderJsCallback *cb = new(std::nothrow) AVTransCoderJsCallback();
110 CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
111 cb->autoRef = refMap_.at(AVTransCoderEvent::EVENT_PROGRESS_UPDATE);
112 cb->callbackName = AVTransCoderEvent::EVENT_PROGRESS_UPDATE;
113 cb->progress = progress;
114 return OnJsProgressUpdateCallback(cb);
115 }
116
OnError(int32_t errCode,const std::string & errorMsg)117 void AVTransCoderCallback::OnError(int32_t errCode, const std::string &errorMsg)
118 {
119 MEDIA_LOGE("AVTransCoderCallback::OnError: %{public}d, %{public}s", errCode, errorMsg.c_str());
120 MediaServiceExtErrCodeAPI9 errorCodeApi9 = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errCode));
121 SendErrorCallback(errorCodeApi9, errorMsg);
122 SendStateCallback(AVTransCoderState::STATE_ERROR, StateChangeReason::BACKGROUND);
123 }
124
OnInfo(int32_t type,int32_t extra)125 void AVTransCoderCallback::OnInfo(int32_t type, int32_t extra)
126 {
127 if (type == TransCoderOnInfoType::INFO_TYPE_TRANSCODER_COMPLETED) {
128 SendCompleteCallback();
129 } else if (type == TransCoderOnInfoType::INFO_TYPE_PROGRESS_UPDATE) {
130 SendProgressUpdateCallback(extra);
131 }
132 }
133
OnJsCompleteCallBack(AVTransCoderJsCallback * jsCb) const134 void AVTransCoderCallback::OnJsCompleteCallBack(AVTransCoderJsCallback *jsCb) const
135 {
136 auto task = [event = jsCb]() {
137 // Js Thread
138 CHECK_AND_RETURN_LOG(event != nullptr, "jsCb is nullptr");
139 std::string request = event->callbackName;
140 MEDIA_LOGI("uv_queue_work_with_qos start, state changes to %{public}s", event->state.c_str());
141 do {
142 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
143 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
144
145 napi_handle_scope scope = nullptr;
146 napi_open_handle_scope(ref->env_, &scope);
147 CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
148 ON_SCOPE_EXIT(0) {
149 napi_close_handle_scope(ref->env_, scope);
150 };
151
152 napi_value jsCallback = nullptr;
153 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
154 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
155 request.c_str());
156
157 napi_value args[2] = { nullptr };
158
159 const size_t argCount = 0;
160 napi_value result = nullptr;
161 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
162 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
163 } while (0);
164 delete event;
165 };
166
167 auto ret = napi_send_event(env_, task, napi_eprio_immediate);
168 if (ret != napi_status::napi_ok) {
169 MEDIA_LOGE("Failed to SendEvent, ret = %{public}d", ret);
170 delete jsCb;
171 }
172 }
173
OnJsProgressUpdateCallback(AVTransCoderJsCallback * jsCb) const174 void AVTransCoderCallback::OnJsProgressUpdateCallback(AVTransCoderJsCallback *jsCb) const
175 {
176 auto task = [event = jsCb]() {
177 CHECK_AND_RETURN_LOG(event != nullptr, "jsCb is nullptr");
178 std::string request = event->callbackName;
179 do {
180 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
181 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
182
183 napi_handle_scope scope = nullptr;
184 napi_open_handle_scope(ref->env_, &scope);
185 CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
186 ON_SCOPE_EXIT(0) {
187 napi_close_handle_scope(ref->env_, scope);
188 };
189
190 napi_value jsCallback = nullptr;
191 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
192 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
193 request.c_str());
194
195 napi_value args[1] = { nullptr };
196 nstatus = napi_create_int32(ref->env_, event->progress, &args[0]);
197 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
198 "%{public}s fail to create callback", request.c_str());
199
200 const size_t argCount = 1;
201 napi_value result = nullptr;
202 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
203 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
204 } while (0);
205 delete event;
206 };
207
208 auto ret = napi_send_event(env_, task, napi_eprio_immediate);
209 if (ret != napi_status::napi_ok) {
210 MEDIA_LOGE("Failed to SendEvent, ret = %{public}d", ret);
211 delete jsCb;
212 }
213 }
214
GetState()215 std::string AVTransCoderCallback::GetState()
216 {
217 std::lock_guard<std::mutex> lock(mutex_);
218 return currentState_;
219 }
220
OnJsErrorCallBack(AVTransCoderJsCallback * jsCb) const221 void AVTransCoderCallback::OnJsErrorCallBack(AVTransCoderJsCallback *jsCb) const
222 {
223 auto task = [event = jsCb]() {
224 CHECK_AND_RETURN_LOG(event != nullptr, "jsCb is nullptr");
225 std::string request = event->callbackName;
226 MEDIA_LOGI("uv_queue_work_with_qos start, errorcode:%{public}d , errormessage:%{public}s:",
227 event->errorCode, event->errorMsg.c_str());
228 do {
229 std::shared_ptr<AutoRef> ref = event->autoRef.lock();
230 CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
231
232 napi_handle_scope scope = nullptr;
233 napi_open_handle_scope(ref->env_, &scope);
234 CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
235 ON_SCOPE_EXIT(0) {
236 napi_close_handle_scope(ref->env_, scope);
237 };
238
239 napi_value jsCallback = nullptr;
240 napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
241 CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
242 request.c_str());
243
244 napi_value msgValStr = nullptr;
245 nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
246 CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
247
248 napi_value args[1] = { nullptr };
249 nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
250 CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
251
252 nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
253 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "create error callback fail");
254
255 // Call back function
256 napi_value result = nullptr;
257 nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
258 CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
259 } while (0);
260 delete event;
261 };
262
263 auto ret = napi_send_event(env_, task, napi_eprio_immediate);
264 if (ret != napi_status::napi_ok) {
265 MEDIA_LOGE("Failed to SendEvent, ret = %{public}d", ret);
266 delete jsCb;
267 }
268 }
269 } // namespace Media
270 } // namespace OHOS