• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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