• 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_value jsCallback = nullptr;
154             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
155             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
156                 request.c_str());
157 
158             napi_value args[2] = { nullptr };
159             nstatus = napi_create_string_utf8(ref->env_, event->state.c_str(), NAPI_AUTO_LENGTH, &args[0]);
160             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr,
161                 "%{public}s fail to create callback", request.c_str());
162 
163             nstatus = napi_create_int32(ref->env_, event->reason, &args[1]);
164             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[1] != nullptr,
165                 "%{public}s fail to create callback", request.c_str());
166 
167             const size_t argCount = 2;
168             napi_value result = nullptr;
169             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, argCount, args, &result);
170             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
171         } while (0);
172         delete event;
173         delete work;
174     });
175     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
176 
177     CANCEL_SCOPE_EXIT_GUARD(0);
178     CANCEL_SCOPE_EXIT_GUARD(1);
179 }
180 
OnJsErrorCallBack(AVRecordJsCallback * jsCb) const181 void AVRecorderCallback::OnJsErrorCallBack(AVRecordJsCallback *jsCb) const
182 {
183     ON_SCOPE_EXIT(0) {
184         delete jsCb;
185     };
186 
187     uv_loop_s *loop = nullptr;
188     napi_get_uv_event_loop(env_, &loop);
189     CHECK_AND_RETURN_LOG(loop != nullptr, "Fail to get uv event loop");
190 
191     uv_work_t *work = new(std::nothrow) uv_work_t;
192     CHECK_AND_RETURN_LOG(work != nullptr, "fail to new uv_work_t");
193     ON_SCOPE_EXIT(1) {
194         delete work;
195     };
196 
197     work->data = reinterpret_cast<void *>(jsCb);
198     // async callback, jsWork and jsWork->data should be heap object.
199     int ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int status) {
200         // Js Thread
201         CHECK_AND_RETURN_LOG(work != nullptr, "work is nullptr");
202         CHECK_AND_RETURN_LOG(work->data != nullptr, "workdata is nullptr");
203         AVRecordJsCallback *event = reinterpret_cast<AVRecordJsCallback *>(work->data);
204         std::string request = event->callbackName;
205         MEDIA_LOGI("uv_queue_work start, errorcode:%{public}d , errormessage:%{public}s:",
206             event->errorCode, event->errorMsg.c_str());
207         do {
208             CHECK_AND_BREAK_LOG(status != UV_ECANCELED, "%{public}s canceled", request.c_str());
209             std::shared_ptr<AutoRef> ref = event->autoRef.lock();
210             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", request.c_str());
211 
212             napi_value jsCallback = nullptr;
213             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
214             CHECK_AND_BREAK_LOG(nstatus == napi_ok && jsCallback != nullptr, "%{public}s get reference value fail",
215                 request.c_str());
216 
217             napi_value msgValStr = nullptr;
218             nstatus = napi_create_string_utf8(ref->env_, event->errorMsg.c_str(), NAPI_AUTO_LENGTH, &msgValStr);
219             CHECK_AND_BREAK_LOG(nstatus == napi_ok && msgValStr != nullptr, "create error message str fail");
220 
221             napi_value args[1] = { nullptr };
222             nstatus = napi_create_error(ref->env_, nullptr, msgValStr, &args[0]);
223             CHECK_AND_BREAK_LOG(nstatus == napi_ok && args[0] != nullptr, "create error callback fail");
224 
225             nstatus = CommonNapi::FillErrorArgs(ref->env_, event->errorCode, args[0]);
226             CHECK_AND_RETURN_LOG(nstatus == napi_ok, "create error callback fail");
227 
228             // Call back function
229             napi_value result = nullptr;
230             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, 1, args, &result);
231             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "%{public}s fail to napi call function", request.c_str());
232         } while (0);
233         delete event;
234         delete work;
235     });
236     CHECK_AND_RETURN_LOG(ret == 0, "fail to uv_queue_work task");
237 
238     CANCEL_SCOPE_EXIT_GUARD(0);
239     CANCEL_SCOPE_EXIT_GUARD(1);
240 }
241 } // namespace Media
242 } // namespace OHOS