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
16 #include "avmetadatahelper_callback.h"
17 #include <uv.h>
18 #include "media_errors.h"
19 #include "media_log.h"
20 #include "scope_guard.h"
21 #include "event_queue.h"
22
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_METADATA, "AVMetadataHelperCallback"};
25 }
26
27 namespace OHOS {
28 namespace Media {
29 class NapiCallback {
30 public:
31 struct Base {
32 std::weak_ptr<AutoRef> callback;
33 std::string callbackName = "unknown";
34 Base() = default;
35 virtual ~Base() = default;
UvWorkOHOS::Media::NapiCallback::Base36 virtual void UvWork()
37 {
38 std::shared_ptr<AutoRef> ref = callback.lock();
39 CHECK_AND_RETURN_LOG(ref != nullptr,
40 "%{public}s AutoRef is nullptr", callbackName.c_str());
41
42 napi_handle_scope scope = nullptr;
43 napi_open_handle_scope(ref->env_, &scope);
44 CHECK_AND_RETURN_LOG(scope != nullptr,
45 "%{public}s scope is nullptr", callbackName.c_str());
46 ON_SCOPE_EXIT(0) {
47 napi_close_handle_scope(ref->env_, scope);
48 };
49
50 napi_value jsCallback = nullptr;
51 napi_status status = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
52 CHECK_AND_RETURN_LOG(status == napi_ok && jsCallback != nullptr,
53 "%{public}s failed to napi_get_reference_value", callbackName.c_str());
54
55 // Call back function
56 napi_value result = nullptr;
57 status = napi_call_function(ref->env_, nullptr, jsCallback, 0, nullptr, &result);
58 CHECK_AND_RETURN_LOG(status == napi_ok,
59 "%{public}s failed to napi_call_function", callbackName.c_str());
60 }
JsCallbackOHOS::Media::NapiCallback::Base61 virtual void JsCallback()
62 {
63 UvWork();
64 delete this;
65 }
66 };
67
68 struct Error : public Base {
69 std::string errorMsg = "unknown";
70 MediaServiceExtErrCodeAPI9 errorCode = MSERR_EXT_API9_UNSUPPORT_FORMAT;
UvWorkOHOS::Media::NapiCallback::Error71 void UvWork() override
72 {
73 std::shared_ptr<AutoRef> ref = callback.lock();
74 CHECK_AND_RETURN_LOG(ref != nullptr,
75 "%{public}s AutoRef is nullptr", callbackName.c_str());
76
77 napi_handle_scope scope = nullptr;
78 napi_open_handle_scope(ref->env_, &scope);
79 CHECK_AND_RETURN_LOG(scope != nullptr,
80 "%{public}s scope is nullptr", callbackName.c_str());
81 ON_SCOPE_EXIT(0) {
82 napi_close_handle_scope(ref->env_, scope);
83 };
84
85 napi_value jsCallback = nullptr;
86 napi_status status = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
87 CHECK_AND_RETURN_LOG(status == napi_ok && jsCallback != nullptr,
88 "%{public}s failed to napi_get_reference_value", callbackName.c_str());
89
90 napi_value args[1] = {nullptr};
91 (void)CommonNapi::CreateError(ref->env_, errorCode, errorMsg, args[0]);
92
93 // Call back function
94 napi_value result = nullptr;
95 status = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
96 CHECK_AND_RETURN_LOG(status == napi_ok,
97 "%{public}s failed to napi_call_function", callbackName.c_str());
98 }
99 };
100
CompleteCallback(napi_env env,NapiCallback::Base * jsCb)101 static void CompleteCallback(napi_env env, NapiCallback::Base *jsCb)
102 {
103 ON_SCOPE_EXIT(0) {
104 delete jsCb;
105 };
106
107 uv_loop_s *loop = nullptr;
108 napi_get_uv_event_loop(env, &loop);
109 CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to napi_get_uv_event_loop");
110
111 uv_work_t *work = new(std::nothrow) uv_work_t;
112 CHECK_AND_RETURN_LOG(work != nullptr, "Fail to new uv_work_t");
113
114 work->data = reinterpret_cast<void *>(jsCb);
115 // async callback, jsWork and jsWork->data should be heap object.
116 int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
117 CHECK_AND_RETURN_LOG(work != nullptr, "Work thread is nullptr");
118 (void)status;
119 NapiCallback::Base *cb = reinterpret_cast<NapiCallback::Base *>(work->data);
120 if (cb != nullptr) {
121 MEDIA_LOGI("JsCallBack %{public}s, uv_queue_work start", cb->callbackName.c_str());
122 cb->UvWork();
123 delete cb;
124 }
125 delete work;
126 });
127 if (ret != 0) {
128 MEDIA_LOGE("Failed to execute libuv work queue");
129 delete jsCb;
130 delete work;
131 }
132 CANCEL_SCOPE_EXIT_GUARD(0);
133 }
134 };
135
AVMetadataHelperCallback(napi_env env,AVMetadataHelperNotify * listener)136 AVMetadataHelperCallback::AVMetadataHelperCallback(napi_env env, AVMetadataHelperNotify *listener)
137 : env_(env), listener_(listener)
138 {
139 onInfoFuncs_[HELPER_INFO_TYPE_STATE_CHANGE] =
140 [this](const int32_t extra, const Format &infoBody) { OnStateChangeCb(extra, infoBody); };
141 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
142 }
143
~AVMetadataHelperCallback()144 AVMetadataHelperCallback::~AVMetadataHelperCallback()
145 {
146 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
147 }
148
OnError(int32_t errorCode,const std::string & errorMsg)149 void AVMetadataHelperCallback::OnError(int32_t errorCode, const std::string &errorMsg)
150 {
151 if (errorCode == HelperErrorType::INVALID_RESULT) {
152 MEDIA_LOGE("OnError: errorCode %{public}d, errorMsg %{public}s", errorCode, errorMsg.c_str());
153 AVMetadataHelperCallback::OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, errorMsg);
154 return;
155 }
156 MediaServiceExtErrCodeAPI9 errorCodeApi9 = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errorCode));
157 AVMetadataHelperCallback::OnErrorCb(errorCodeApi9, errorMsg);
158 }
159
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)160 void AVMetadataHelperCallback::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
161 {
162 std::string message = MSExtAVErrorToString(errorCode) + errorMsg;
163 MEDIA_LOGE("OnErrorCb:errorCode %{public}d, errorMsg %{public}s", errorCode, message.c_str());
164 std::lock_guard<std::mutex> lock(mutex_);
165 if (refMap_.find(AVMetadataHelperEvent::EVENT_ERROR) == refMap_.end()) {
166 MEDIA_LOGW("can not find error callback!");
167 return;
168 }
169
170 NapiCallback::Error *cb = new(std::nothrow) NapiCallback::Error();
171 CHECK_AND_RETURN_LOG(cb != nullptr, "failed to new Error");
172
173 cb->callback = refMap_.at(AVMetadataHelperEvent::EVENT_ERROR);
174 cb->callbackName = AVMetadataHelperEvent::EVENT_ERROR;
175 cb->errorCode = errorCode;
176 cb->errorMsg = message;
177 NapiCallback::CompleteCallback(env_, cb);
178 }
179
OnInfo(HelperOnInfoType type,int32_t extra,const Format & infoBody)180 void AVMetadataHelperCallback::OnInfo(HelperOnInfoType type, int32_t extra, const Format &infoBody)
181 {
182 std::lock_guard<std::mutex> lock(mutex_);
183 MEDIA_LOGI("OnInfo is called, OnInfoType: %{public}d", type);
184 if (onInfoFuncs_.count(type) > 0) {
185 onInfoFuncs_[type](extra, infoBody);
186 } else {
187 MEDIA_LOGI("OnInfo: no member func supporting, %{public}d", type);
188 }
189 }
190
OnStateChangeCb(const int32_t extra,const Format & infoBody)191 void AVMetadataHelperCallback::OnStateChangeCb(const int32_t extra, const Format &infoBody)
192 {
193 HelperStates state = static_cast<HelperStates>(extra);
194 MEDIA_LOGI("OnStateChanged is called, current state: %{public}d", state);
195
196 if (listener_ != nullptr) {
197 listener_->NotifyState(state);
198 }
199 }
200
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)201 void AVMetadataHelperCallback::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
202 {
203 std::lock_guard<std::mutex> lock(mutex_);
204 refMap_[name] = ref;
205 }
206
ClearCallbackReference()207 void AVMetadataHelperCallback::ClearCallbackReference()
208 {
209 std::lock_guard<std::mutex> lock(mutex_);
210 refMap_.clear();
211 }
212
ClearCallbackReference(const std::string & name)213 void AVMetadataHelperCallback::ClearCallbackReference(const std::string &name)
214 {
215 std::lock_guard<std::mutex> lock(mutex_);
216 refMap_.erase(name);
217 }
218
Start()219 void AVMetadataHelperCallback::Start()
220 {
221 isloaded_ = true;
222 }
223
Pause()224 void AVMetadataHelperCallback::Pause()
225 {
226 isloaded_ = false;
227 }
228
Release()229 void AVMetadataHelperCallback::Release()
230 {
231 std::lock_guard<std::mutex> lock(mutex_);
232
233 Format infoBody;
234 AVMetadataHelperCallback::OnStateChangeCb(HelperStates::HELPER_RELEASED, infoBody);
235 listener_ = nullptr;
236 }
237 } // namespace Media
238 } // namespace OHOS