• 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 "helper_data_source_callback.h"
17 #include "avsharedmemory.h"
18 #include "media_dfx.h"
19 #include "media_log.h"
20 #include "media_errors.h"
21 #include "scope_guard.h"
22 
23 namespace {
24 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_METADATA, "HelperDataSourceCallback"};
25 }
26 
27 namespace OHOS {
28 namespace Media {
29 const std::string HELPER_READAT_CALLBACK_NAME = "readAt";
30 
~HelperDataSourceJsCallback()31 HelperDataSourceJsCallback::~HelperDataSourceJsCallback()
32 {
33     isExit_ = true;
34     cond_.notify_all();
35     memory_ = nullptr;
36 }
37 
WaitResult()38 void HelperDataSourceJsCallback::WaitResult()
39 {
40     std::unique_lock<std::mutex> lock(mutexCond_);
41     if (!setResult_) {
42         static constexpr int32_t timeout = 100;
43         cond_.wait_for(lock, std::chrono::milliseconds(timeout), [this]() { return setResult_ || isExit_; });
44         if (!setResult_) {
45             readSize_ = 0;
46             if (isExit_) {
47                 MEDIA_LOGW("Reset, ReadAt has been cancel!");
48             } else {
49                 MEDIA_LOGW("timeout 100ms!");
50             }
51         }
52     }
53     setResult_ = false;
54 }
55 
HelperDataSourceCallback(napi_env env,int64_t fileSize)56 HelperDataSourceCallback::HelperDataSourceCallback(napi_env env, int64_t fileSize)
57     : env_(env),
58       size_(fileSize)
59 {
60     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
61 }
62 
~HelperDataSourceCallback()63 HelperDataSourceCallback::~HelperDataSourceCallback()
64 {
65     MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
66     env_ = nullptr;
67 }
68 
ReadAt(const std::shared_ptr<AVSharedMemory> & mem,uint32_t length,int64_t pos)69 int32_t HelperDataSourceCallback::ReadAt(const std::shared_ptr<AVSharedMemory> &mem, uint32_t length, int64_t pos)
70 {
71     MEDIA_LOGD("ReadAt in");
72     {
73         std::lock_guard<std::mutex> lock(mutex_);
74         if (refMap_.find(HELPER_READAT_CALLBACK_NAME) == refMap_.end()) {
75             return SOURCE_ERROR_IO;
76         }
77         cb_ = std::make_shared<HelperDataSourceJsCallback>(HELPER_READAT_CALLBACK_NAME, mem, length, pos);
78         CHECK_AND_RETURN_RET_LOG(cb_ != nullptr, 0, "Failed to Create HelperDataSourceJsCallback");
79         cb_->callback_ = refMap_.at(HELPER_READAT_CALLBACK_NAME);
80     }
81     ON_SCOPE_EXIT(0) {
82         cb_ = nullptr;
83     };
84 
85     HelperDataSourceJsCallbackWraper *cbWrap = new(std::nothrow) HelperDataSourceJsCallbackWraper();
86     ON_SCOPE_EXIT(1) {
87         if (cbWrap != nullptr) {
88             delete cbWrap;
89         }
90     };
91     CHECK_AND_RETURN_RET_LOG(cbWrap != nullptr, 0, "Failed to new HelperDataSourceJsCallbackWraper");
92     cbWrap->cb_ = cb_;
93 
94     auto ret = UvWork(cbWrap);
95     CHECK_AND_RETURN_RET_LOG(ret == napi_status::napi_ok, SOURCE_ERROR_IO,
96                              "Failed to SendEvent, ret = %{public}d", ret);
97     CANCEL_SCOPE_EXIT_GUARD(1);
98     cb_->WaitResult();
99     MEDIA_LOGD("HelperDataSourceCallback ReadAt out");
100     return cb_->readSize_;
101 }
102 
UvWork(HelperDataSourceJsCallbackWraper * cbWrap)103 napi_status HelperDataSourceCallback::UvWork(HelperDataSourceJsCallbackWraper *cbWrap)
104 {
105     MEDIA_LOGD("begin UvWork");
106     auto task = [cbWrap]() {
107         // Js Thread
108         CHECK_AND_RETURN_LOG(cbWrap != nullptr, "MediaDataSourceJsCallbackWraper is nullptr");
109         std::shared_ptr<HelperDataSourceJsCallback> event = cbWrap->cb_.lock();
110         do {
111             CHECK_AND_BREAK_LOG(event != nullptr, "HelperDataSourceJsCallback is nullptr");
112             MEDIA_LOGD("length is %{public}u", event->length_);
113             std::shared_ptr<AutoRef> ref = event->callback_.lock();
114             CHECK_AND_BREAK_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", event->callbackName_.c_str());
115 
116             napi_handle_scope scope = nullptr;
117             napi_open_handle_scope(ref->env_, &scope);
118             CHECK_AND_BREAK_LOG(scope != nullptr, "%{public}s scope is nullptr", event->callbackName_.c_str());
119             ON_SCOPE_EXIT(0) {
120                 napi_close_handle_scope(ref->env_, scope);
121             };
122 
123             napi_value jsCallback = nullptr;
124             napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
125             CHECK_AND_BREAK(nstatus == napi_ok && jsCallback != nullptr);
126 
127             // noseek mode don't need pos, so noseek mode need 2 parameters and seekable mode need 3 parameters
128             int32_t paramNum;
129             napi_value args[3] = { nullptr };
130             CHECK_AND_BREAK_LOG(event->memory_ != nullptr, "failed to checkout memory");
131             nstatus = napi_create_external_arraybuffer(ref->env_, event->memory_->GetBase(),
132                 static_cast<size_t>(event->length_), [](napi_env env, void *data, void *hint) {}, nullptr, &args[0]);
133             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "create napi arraybuffer failed");
134             CHECK_AND_BREAK_LOG(napi_create_uint32(ref->env_, event->length_, &args[1]) == napi_ok,
135                 "set length failed");
136             if (event->pos_ != -1) {
137                 paramNum = 3;  // 3 parameters
138                 CHECK_AND_BREAK_LOG(napi_create_int64(ref->env_, event->pos_, &args[2]) == napi_ok,  // 2 parameters
139                     "set pos failed");
140             } else {
141                 paramNum = 2;  // 2 parameters
142             }
143 
144             napi_value size;
145             MEDIA_LOGD("call JS function");
146             nstatus = napi_call_function(ref->env_, nullptr, jsCallback, paramNum, args, &size);
147             CHECK_AND_BREAK(nstatus == napi_ok);
148             nstatus = napi_get_value_int32(ref->env_, size, &event->readSize_);
149             CHECK_AND_BREAK_LOG(nstatus == napi_ok, "get size failed");
150             std::unique_lock<std::mutex> lock(event->mutexCond_);
151             event->setResult_ = true;
152             event->cond_.notify_all();
153         } while (0);
154         delete cbWrap;
155     };
156     return napi_send_event(env_, task, napi_eprio_immediate);
157 }
158 
ReadAt(int64_t pos,uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)159 int32_t HelperDataSourceCallback::ReadAt(int64_t pos, uint32_t length, const std::shared_ptr<AVSharedMemory> &mem)
160 {
161     (void)pos;
162     (void)length;
163     (void)mem;
164     return MSERR_OK;
165 }
166 
ReadAt(uint32_t length,const std::shared_ptr<AVSharedMemory> & mem)167 int32_t HelperDataSourceCallback::ReadAt(uint32_t length, const std::shared_ptr<AVSharedMemory> &mem)
168 {
169     (void)length;
170     (void)mem;
171     return MSERR_OK;
172 }
173 
GetSize(int64_t & size)174 int32_t HelperDataSourceCallback::GetSize(int64_t &size)
175 {
176     size = size_;
177     return MSERR_OK;
178 }
179 
SaveCallbackReference(const std::string & name,std::shared_ptr<AutoRef> ref)180 void HelperDataSourceCallback::SaveCallbackReference(const std::string &name, std::shared_ptr<AutoRef> ref)
181 {
182     MEDIA_LOGD("Add Callback: %{public}s", name.c_str());
183     std::lock_guard<std::mutex> lock(mutex_);
184     refMap_[name] = ref;
185 }
186 
GetCallback(const std::string & name,napi_value * callback)187 int32_t HelperDataSourceCallback::GetCallback(const std::string &name, napi_value *callback)
188 {
189     (void)name;
190     if (refMap_.find(HELPER_READAT_CALLBACK_NAME) == refMap_.end()) {
191         return MSERR_INVALID_VAL;
192     }
193     auto ref = refMap_.at(HELPER_READAT_CALLBACK_NAME);
194     napi_status nstatus = napi_get_reference_value(ref->env_, ref->cb_, callback);
195     CHECK_AND_RETURN_RET(nstatus == napi_ok && callback != nullptr, MSERR_INVALID_OPERATION);
196     return MSERR_OK;
197 }
198 
ClearCallbackReference()199 void HelperDataSourceCallback::ClearCallbackReference()
200 {
201     std::lock_guard<std::mutex> lock(mutex_);
202     std::map<std::string, std::shared_ptr<AutoRef>> temp;
203     temp.swap(refMap_);
204     MEDIA_LOGD("callback has been clear");
205     if (cb_) {
206         cb_->isExit_ = true;
207         cb_->cond_.notify_all();
208     }
209 }
210 
AddNapiValueProp(napi_env env,napi_value obj,const std::string & key,napi_value value)211 bool HelperDataSourceCallback::AddNapiValueProp(napi_env env, napi_value obj, const std::string &key, napi_value value)
212 {
213     CHECK_AND_RETURN_RET(obj != nullptr, false);
214 
215     napi_value keyNapi = nullptr;
216     napi_status status = napi_create_string_utf8(env, key.c_str(), NAPI_AUTO_LENGTH, &keyNapi);
217     CHECK_AND_RETURN_RET(status == napi_ok, false);
218 
219     status = napi_set_property(env, obj, keyNapi, value);
220     CHECK_AND_RETURN_RET_LOG(status == napi_ok, false, "Failed to set property");
221 
222     return true;
223 }
224 } // namespace Media
225 } // namespace OHOS
226