• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "avrecorder_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, "AVRecorderCallback"};
23 }
24 
25 namespace OHOS {
26 namespace Media {
AVRecorderCallback(napi_env env)27 AVRecorderCallback::AVRecorderCallback(napi_env env) : env_(env)
28 {
29     MEDIA_LOGI("0x%{public}06" PRIXPTR "Instances create", FAKE_POINTER(this));
30 }
31 
~AVRecorderCallback()32 AVRecorderCallback::~AVRecorderCallback()
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 AVRecorderCallback::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 AVRecorderCallback::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 AVRecorderCallback::ClearCallbackReference()
55 {
56     std::lock_guard<std::mutex> lock(mutex_);
57     refMap_.clear();
58     MEDIA_LOGI("ClearCallback!");
59 }
60 
SendErrorCallback(int32_t errCode,const std::string & msg)61 void AVRecorderCallback::SendErrorCallback(int32_t errCode, const std::string &msg)
62 {
63     std::lock_guard<std::mutex> lock(mutex_);
64     if (refMap_.find(AVRecorderEvent::EVENT_ERROR) == refMap_.end()) {
65         MEDIA_LOGW("can not find error callback!");
66         return;
67     }
68 
69     AVRecordJsCallback *cb = new(std::nothrow) AVRecordJsCallback();
70     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
71     cb->autoRef = refMap_.at(AVRecorderEvent::EVENT_ERROR);
72     cb->callbackName = AVRecorderEvent::EVENT_ERROR;
73     cb->errorCode = errCode;
74     cb->errorMsg = msg;
75     return OnJsErrorCallBack(cb);
76 }
77 
SendStateCallback(const std::string & state,const StateChangeReason & reason)78 void AVRecorderCallback::SendStateCallback(const std::string &state, const StateChangeReason &reason)
79 {
80     std::lock_guard<std::mutex> lock(mutex_);
81     currentState_ = state;
82     if (refMap_.find(AVRecorderEvent::EVENT_STATE_CHANGE) == refMap_.end()) {
83         MEDIA_LOGW("can not find statechange callback!");
84         return;
85     }
86 
87     AVRecordJsCallback *cb = new(std::nothrow) AVRecordJsCallback();
88     CHECK_AND_RETURN_LOG(cb != nullptr, "cb is nullptr");
89     cb->autoRef = refMap_.at(AVRecorderEvent::EVENT_STATE_CHANGE);
90     cb->callbackName = AVRecorderEvent::EVENT_STATE_CHANGE;
91     cb->reason = reason;
92     cb->state = state;
93     return OnJsStateCallBack(cb);
94 }
95 
GetState()96 std::string AVRecorderCallback::GetState()
97 {
98     std::lock_guard<std::mutex> lock(mutex_);
99     return currentState_;
100 }
101 
OnError(RecorderErrorType errorType,int32_t errCode)102 void AVRecorderCallback::OnError(RecorderErrorType errorType, int32_t errCode)
103 {
104     MEDIA_LOGI("OnError is called, name: %{public}d, error message: %{public}d", errorType, errCode);
105     if (errCode == MSERR_DATA_SOURCE_IO_ERROR) {
106         SendErrorCallback(MSERR_EXT_API9_TIMEOUT,
107             "The video input stream timed out. Please confirm that the input stream is normal.");
108     } else if (errCode == MSERR_DATA_SOURCE_OBTAIN_MEM_ERROR) {
109         SendErrorCallback(MSERR_EXT_API9_TIMEOUT,
110             "Read data from audio timeout, please confirm whether the audio module is normal.");
111     } else if (errCode == MSERR_DATA_SOURCE_ERROR_UNKNOWN) {
112         SendErrorCallback(MSERR_EXT_API9_IO, "Video input data is abnormal."
113             " Please confirm that the pts, width, height, size and other data are normal.");
114     } else {
115         SendErrorCallback(MSERR_EXT_API9_IO, "IO error happened.");
116     }
117     SendStateCallback(AVRecorderState::STATE_ERROR, StateChangeReason::BACKGROUND);
118 }
119 
OnInfo(int32_t type,int32_t extra)120 void AVRecorderCallback::OnInfo(int32_t type, int32_t extra)
121 {
122     MEDIA_LOGI("OnInfo() is called, type: %{public}d, extra: %{public}d", type, extra);
123 }
124 
OnJsStateCallBack(AVRecordJsCallback * jsCb) const125 void AVRecorderCallback::OnJsStateCallBack(AVRecordJsCallback *jsCb) const
126 {
127     ON_SCOPE_EXIT(0) {
128         delete jsCb;
129     };
130 
131     uv_loop_s *loop = nullptr;
132     napi_get_uv_event_loop(env_, &loop);
133     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
134 
135     uv_work_t *work = new(std::nothrow) uv_work_t;
136     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
137     ON_SCOPE_EXIT(1) {
138         delete work;
139     };
140 
141     work->data = reinterpret_cast<void *>(jsCb);
142     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
143         // Js Thread
144         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
145         AVRecordJsCallback *event = reinterpret_cast<AVRecordJsCallback *>(work->data);
146         std::string request = event->callbackName;
147         MEDIA_LOGI("uv_queue_work start, state changes to %{public}s", event->state.c_str());
148         do {
149             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
150             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
151             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
152 
153             napi_handle_scope scope = nullptr;
154             napi_open_handle_scope(ref->env_, &scope);
155             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
156             ON_SCOPE_EXIT(0) { napi_close_handle_scope(ref->env_, scope); };
157 
158             napi_value jsCallback = nullptr;
159             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
160             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
161                 request.c_str());
162 
163             napi_value args[2] = { nullptr };
164             nstatus = napi_create_string_utf8(ref->env_, event->state.c_str(), NAPI_AUTO_LENGTH, &args[0]);
165             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
166                 "%{public}s fail to create callback", request.c_str());
167 
168             nstatus = napi_create_int32(ref->env_, event->reason, &args[1]);
169             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[1] != nullptr,
170                 "%{public}s fail to create callback", request.c_str());
171 
172             const size_t argCount = 2;
173             napi_value result = nullptr;
174             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
175             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
176         } while (0);
177         delete event;
178         delete work;
179     });
180     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
181 
182     CANCEL_SCOPE_EXIT_GUARD(0);
183     CANCEL_SCOPE_EXIT_GUARD(1);
184 }
185 
OnJsErrorCallBack(AVRecordJsCallback * jsCb) const186 void AVRecorderCallback::OnJsErrorCallBack(AVRecordJsCallback *jsCb) const
187 {
188     ON_SCOPE_EXIT(0) {
189         delete jsCb;
190     };
191 
192     uv_loop_s *loop = nullptr;
193     napi_get_uv_event_loop(env_, &loop);
194     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
195 
196     uv_work_t *work = new(std::nothrow) uv_work_t;
197     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
198     ON_SCOPE_EXIT(1) {
199         delete work;
200     };
201 
202     work->data = reinterpret_cast<void *>(jsCb);
203     // async callback, jsWork and jsWork->data should be heap object.
204     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
205         // Js Thread
206         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
207         CHECK_AND_RETURN_LOG(work->data != nullptr, "workdata is nullptr");
208         AVRecordJsCallback *event = reinterpret_cast<AVRecordJsCallback *>(work->data);
209         std::string request = event->callbackName;
210         MEDIA_LOGI("uv_queue_work start, errorcode:%{public}d , errormessage:%{public}s:",
211             event->errorCode, event->errorMsg.c_str());
212         do {
213             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
214             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
215             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
216 
217             napi_handle_scope scope = nullptr;
218             napi_open_handle_scope(ref->env_, &scope);
219             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", request.c_str());
220             ON_SCOPE_EXIT(0) { napi_close_handle_scope(ref->env_, scope); };
221 
222             napi_value jsCallback = nullptr;
223             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
224             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
225                 request.c_str());
226 
227             napi_value msgValStr = nullptr;
228             nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
229             CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
230 
231             napi_value args[1] = { nullptr };
232             nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
233             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
234 
235             nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
236             CHECK_AND_RETURN_LOG(nstatus == napi_ok, "create error callback fail");
237 
238             // Call back function
239             napi_value result = nullptr;
240             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
241             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
242         } while (0);
243         delete event;
244         delete work;
245     });
246     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
247 
248     CANCEL_SCOPE_EXIT_GUARD(0);
249     CANCEL_SCOPE_EXIT_GUARD(1);
250 }
251 } // namespace Media
252 } // namespace OHOS