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