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 CHECK_AND_RETURN(jsCb != nullptr);
104 napi_status ret = napi_send_event(env, [jsCb] () {
105 CHECK_AND_RETURN_LOG(jsCb != nullptr, "jsCb is nullptr");
106 MEDIA_LOGI("JsCallBack %{public}s start", jsCb->callbackName.c_str());
107 jsCb->UvWork();
108 delete jsCb;
109 }, napi_eprio_high);
110 if (ret != napi_ok) {
111 MEDIA_LOGE("Failed to execute libuv work queue, ret = %{public}d", ret);
112 delete jsCb;
113 }
114 }
115 };
116
AVMetadataHelperCallback(napi_env env,AVMetadataHelperNotify * listener)117 AVMetadataHelperCallback::AVMetadataHelperCallback(napi_env env, AVMetadataHelperNotify *listener)
118 : env_(env), listener_(listener)
119 {
120 onInfoFuncs_[HELPER_INFO_TYPE_STATE_CHANGE] =
121 [this](const int32_t extra, const Format &infoBody) { OnStateChangeCb(extra, infoBody); };
122 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
123 }
124
~AVMetadataHelperCallback()125 AVMetadataHelperCallback::~AVMetadataHelperCallback()
126 {
127 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
128 }
129
OnError(int32_t errorCode,const std::string & errorMsg)130 void AVMetadataHelperCallback::OnError(int32_t errorCode, const std::string &errorMsg)
131 {
132 if (errorCode == HelperErrorType::INVALID_RESULT) {
133 MEDIA_LOGE("OnError: errorCode %{public}d, errorMsg %{public}s", errorCode, errorMsg.c_str());
134 AVMetadataHelperCallback::OnErrorCb(MSERR_EXT_API9_OPERATE_NOT_PERMIT, errorMsg);
135 return;
136 }
137 MediaServiceExtErrCodeAPI9 errorCodeApi9 = MSErrorToExtErrorAPI9(static_cast<MediaServiceErrCode>(errorCode));
138 AVMetadataHelperCallback::OnErrorCb(errorCodeApi9, errorMsg);
139 }
140
OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode,const std::string & errorMsg)141 void AVMetadataHelperCallback::OnErrorCb(MediaServiceExtErrCodeAPI9 errorCode, const std::string &errorMsg)
142 {
143 std::string message = MSExtAVErrorToString(errorCode) + errorMsg;
144 MEDIA_LOGE("OnErrorCb:errorCode %{public}d, errorMsg %{public}s", errorCode, message.c_str());
145 std::lock_guard<std::mutex> lock(mutex_);
146 if (refMap_.find(AVMetadataHelperEvent::EVENT_ERROR) == refMap_.end()) {
147 MEDIA_LOGW("can not find error callback!");
148 return;
149 }
150
151 NapiCallback::Error *cb = new(std::nothrow) NapiCallback::Error();
152 CHECK_AND_RETURN_LOG(cb != nullptr, "failed to new Error");
153
154 cb->callback = refMap_.at(AVMetadataHelperEvent::EVENT_ERROR);
155 cb->callbackName = AVMetadataHelperEvent::EVENT_ERROR;
156 cb->errorCode = errorCode;
157 cb->errorMsg = message;
158 NapiCallback::CompleteCallback(env_, cb);
159 }
160
OnInfo(HelperOnInfoType type,int32_t extra,const Format & infoBody)161 void AVMetadataHelperCallback::OnInfo(HelperOnInfoType type, int32_t extra, const Format &infoBody)
162 {
163 std::lock_guard<std::mutex> lock(mutex_);
164 MEDIA_LOGI("OnInfo is called, OnInfoType: %{public}d", type);
165 if (onInfoFuncs_.count(type) > 0) {
166 onInfoFuncs_[type](extra, infoBody);
167 } else {
168 MEDIA_LOGI("OnInfo: no member func supporting, %{public}d", type);
169 }
170 }
171
OnStateChangeCb(const int32_t extra,const Format & infoBody)172 void AVMetadataHelperCallback::OnStateChangeCb(const int32_t extra, const Format &infoBody)
173 {
174 HelperStates state = static_cast<HelperStates>(extra);
175 MEDIA_LOGI("OnStateChanged is called, current state: %{public}d", state);
176
177 if (listener_ != nullptr) {
178 listener_->NotifyState(state);
179 }
180 }
181
SaveCallbackReference(const std::string & name,std::weak_ptr<AutoRef> ref)182 void AVMetadataHelperCallback::SaveCallbackReference(const std::string &name, std::weak_ptr<AutoRef> ref)
183 {
184 std::lock_guard<std::mutex> lock(mutex_);
185 refMap_[name] = ref;
186 }
187
ClearCallbackReference()188 void AVMetadataHelperCallback::ClearCallbackReference()
189 {
190 std::lock_guard<std::mutex> lock(mutex_);
191 refMap_.clear();
192 }
193
ClearCallbackReference(const std::string & name)194 void AVMetadataHelperCallback::ClearCallbackReference(const std::string &name)
195 {
196 std::lock_guard<std::mutex> lock(mutex_);
197 refMap_.erase(name);
198 }
199
Start()200 void AVMetadataHelperCallback::Start()
201 {
202 isloaded_ = true;
203 }
204
Pause()205 void AVMetadataHelperCallback::Pause()
206 {
207 isloaded_ = false;
208 }
209
Release()210 void AVMetadataHelperCallback::Release()
211 {
212 std::lock_guard<std::mutex> lock(mutex_);
213
214 Format infoBody;
215 AVMetadataHelperCallback::OnStateChangeCb(HelperStates::HELPER_RELEASED, infoBody);
216 listener_ = nullptr;
217 }
218 } // namespace Media
219 } // namespace OHOS