1 /*
2 * Copyright (C) 2025 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 "media_source_loader_callback.h"
17 #include "buffer/avsharedmemory.h"
18 #include "media_dfx.h"
19 #include "media_log.h"
20 #include "media_errors.h"
21 #include "loading_request.h"
22 #include "scope_guard.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "MediaSourceLoaderCallback"};
26 constexpr size_t ARRAY_ARG_COUNTS_ONE = 1;
27 constexpr size_t ARRAY_ARG_COUNTS_THREE = 3;
28 constexpr int32_t INDEX_A = 0;
29 constexpr int32_t INDEX_B = 1;
30 constexpr int32_t INDEX_C = 2;
31 }
32
33 namespace OHOS {
34 namespace Media {
~MediaDataSourceLoaderJsCallback()35 MediaDataSourceLoaderJsCallback::~MediaDataSourceLoaderJsCallback()
36 {
37 isExit_ = true;
38 cond_.notify_all();
39 }
40
WaitResult()41 void MediaDataSourceLoaderJsCallback::WaitResult()
42 {
43 std::unique_lock<std::mutex> lock(mutexCond_);
44 if (!setResult_) {
45 static constexpr int32_t timeout = 200;
46 cond_.wait_for(lock, std::chrono::milliseconds(timeout), [this]() { return setResult_ || isExit_; });
47 if (!setResult_) {
48 uuid_ = 0;
49 if (isExit_) {
50 MEDIA_LOGW("Reset, OPen has been cancel!");
51 } else {
52 MEDIA_LOGW("timeout 100ms!");
53 }
54 }
55 }
56 setResult_ = false;
57 }
58
MediaSourceLoaderCallback(napi_env env)59 MediaSourceLoaderCallback::MediaSourceLoaderCallback(napi_env env)
60 : env_(env)
61 {
62 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
63 }
64
~MediaSourceLoaderCallback()65 MediaSourceLoaderCallback::~MediaSourceLoaderCallback()
66 {
67 MEDIA_LOGD("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
68 env_ = nullptr;
69 }
70
Open(std::shared_ptr<LoadingRequest> & request)71 int64_t MediaSourceLoaderCallback::Open(std::shared_ptr<LoadingRequest> &request)
72 {
73 MediaTrace trace("MediaSourceLoaderCallback::open");
74 MEDIA_LOGI("<< open");
75 std::lock_guard<std::mutex> lock(mutex_);
76
77 if (refMap_.find(FunctionName::SOURCE_OPEN) == refMap_.end()) {
78 MEDIA_LOGE("can not find read callback!");
79 return 0;
80 }
81
82 jsCb_ = std::make_shared<MediaDataSourceLoaderJsCallback>();
83 CHECK_AND_RETURN_RET_LOG(jsCb_ != nullptr, 0, "cb is nullptr");
84 jsCb_->autoRef_ = refMap_.at(FunctionName::SOURCE_OPEN);
85 jsCb_->callbackName_ = FunctionName::SOURCE_OPEN;
86 jsCb_->request_ = request;
87
88 napi_status ret = napi_send_event(env_, [jsCb = jsCb_] () {
89 CHECK_AND_RETURN_LOG(jsCb != nullptr, "request is nullptr");
90 MEDIA_LOGD("CallBack %{public}s start", jsCb->callbackName_.c_str());
91 do {
92 std::shared_ptr<AutoRef> ref = jsCb->autoRef_.lock();
93 CHECK_AND_RETURN_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", jsCb->callbackName_.c_str());
94 napi_handle_scope scope = nullptr;
95 napi_open_handle_scope(ref->env_, &scope);
96 CHECK_AND_RETURN_LOG(scope != nullptr, "%{public}s scope is nullptr", jsCb->callbackName_.c_str());
97 ON_SCOPE_EXIT(0) {
98 napi_close_handle_scope(ref->env_, scope);
99 };
100 napi_value jsCallback = nullptr;
101 napi_status napiStatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
102 CHECK_AND_RETURN_LOG(napiStatus == napi_ok && jsCallback != nullptr,
103 "%{public}s failed to napi_get_reference_value", jsCb->callbackName_.c_str());
104
105 napi_value args[ARRAY_ARG_COUNTS_ONE] = { nullptr };
106 args[0] = MediaSourceLoadingRequestNapi::CreateLoadingRequest(ref->env_, jsCb->request_);
107
108 napi_value result = nullptr;
109 napiStatus = napi_call_function(ref->env_, nullptr, jsCallback, ARRAY_ARG_COUNTS_ONE, args, &result);
110 CHECK_AND_RETURN_LOG(napiStatus == napi_ok, "%{public}s failed to napi_call_function",
111 jsCb->callbackName_.c_str());
112 napiStatus = napi_get_value_int64(ref->env_, result, &jsCb->uuid_);
113 CHECK_AND_BREAK_LOG(napiStatus == napi_ok, "get uuid failed");
114 std::unique_lock<std::mutex> lock(jsCb->mutexCond_);
115 jsCb->setResult_ = true;
116 jsCb->cond_.notify_all();
117 } while (0);
118 }, napi_eprio_immediate);
119 if (ret != napi_ok) {
120 MEDIA_LOGE("Failed to execute libuv work queue");
121 return jsCb_->uuid_;
122 }
123 jsCb_->WaitResult();
124 MEDIA_LOGI("MediaSourceLoaderCallback open out");
125 return jsCb_->uuid_;
126 }
127
Read(int64_t uuid,int64_t requestedOffset,int64_t requestedLength)128 void MediaSourceLoaderCallback::Read(int64_t uuid, int64_t requestedOffset, int64_t requestedLength)
129 {
130 MediaTrace trace("MediaSourceLoaderCallback::read, uuid: " + std::to_string(uuid) +
131 " offset: " + std::to_string(requestedOffset) + " Length:" + std::to_string(requestedLength));
132 MEDIA_LOGI("<< read");
133 std::lock_guard<std::mutex> lock(mutex_);
134
135 if (refMap_.find(FunctionName::SOURCE_READ) == refMap_.end()) {
136 MEDIA_LOGE("can not find read callback!");
137 return;
138 }
139
140 jsCb_ = std::make_shared<MediaDataSourceLoaderJsCallback>();
141 CHECK_AND_RETURN_LOG(jsCb_ != nullptr, "cb is nullptr");
142
143 jsCb_->autoRef_ = refMap_.at(FunctionName::SOURCE_READ);
144 jsCb_->callbackName_ = FunctionName::SOURCE_READ;
145 jsCb_->uuid_ = uuid;
146 jsCb_->requestedOffset_ = requestedOffset;
147 jsCb_->requestedLength_ = requestedLength;
148
149 napi_status ret = napi_send_event(env_, [jsCb = jsCb_] () {
150 CHECK_AND_RETURN_LOG(jsCb != nullptr, "request is nullptr");
151 MEDIA_LOGD("CallBack %{public}s start", jsCb->callbackName_.c_str());
152 do {
153 std::shared_ptr<AutoRef> ref = jsCb->autoRef_.lock();
154 CHECK_AND_RETURN_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", jsCb->callbackName_.c_str());
155 napi_handle_scope scope = nullptr;
156 napi_open_handle_scope(ref->env_, &scope);
157 CHECK_AND_RETURN_LOG(scope != nullptr, "%{public}s scope is nullptr", jsCb->callbackName_.c_str());
158 ON_SCOPE_EXIT(0) {
159 napi_close_handle_scope(ref->env_, scope);
160 };
161 napi_value jsCallback = nullptr;
162 napi_status napiStatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
163 CHECK_AND_RETURN_LOG(napiStatus == napi_ok && jsCallback != nullptr,
164 "%{public}s failed to napi_get_reference_value", jsCb->callbackName_.c_str());
165
166 napi_value args[ARRAY_ARG_COUNTS_THREE] = { nullptr };
167 CHECK_AND_BREAK_LOG(napi_create_int64(ref->env_, jsCb->uuid_, &args[INDEX_A]) == napi_ok,
168 "set uuid failed");
169 CHECK_AND_BREAK_LOG(napi_create_int64(ref->env_, jsCb->requestedOffset_, &args[INDEX_B]) == napi_ok,
170 "set requestedOffset failed");
171 CHECK_AND_BREAK_LOG(napi_create_int64(ref->env_, jsCb->requestedLength_, &args[INDEX_C]) == napi_ok,
172 "set requestedLength failed");
173
174 napi_value result = nullptr;
175 napiStatus = napi_call_function(ref->env_, nullptr, jsCallback, ARRAY_ARG_COUNTS_THREE, args, &result);
176 CHECK_AND_RETURN_LOG(napiStatus == napi_ok,
177 "%{public}s failed to napi_call_function", jsCb->callbackName_.c_str());
178 } while (0);
179 }, napi_eprio_immediate);
180 if (ret != napi_ok) {
181 MEDIA_LOGE("Failed to execute libuv work queue");
182 }
183 }
184
Close(int64_t uuid)185 void MediaSourceLoaderCallback::Close(int64_t uuid)
186 {
187 MediaTrace trace("MediaSourceLoaderCallback::close, uuid: " + std::to_string(uuid));
188 MEDIA_LOGI("<< close");
189 std::lock_guard<std::mutex> lock(mutex_);
190
191 if (refMap_.find(FunctionName::SOURCE_CLOSE) == refMap_.end()) {
192 MEDIA_LOGE("can not find read callback!");
193 return;
194 }
195
196 jsCb_ = std::make_shared<MediaDataSourceLoaderJsCallback>();
197 CHECK_AND_RETURN_LOG(jsCb_ != nullptr, "cb is nullptr");
198
199 jsCb_->autoRef_ = refMap_.at(FunctionName::SOURCE_CLOSE);
200 jsCb_->callbackName_ = FunctionName::SOURCE_CLOSE;
201 jsCb_->uuid_ = uuid;
202
203 napi_status ret = napi_send_event(env_, [jsCb = jsCb_] () {
204 CHECK_AND_RETURN_LOG(jsCb != nullptr, "request is nullptr");
205 MEDIA_LOGD("CallBack %{public}s start", jsCb->callbackName_.c_str());
206 do {
207 std::shared_ptr<AutoRef> ref = jsCb->autoRef_.lock();
208 CHECK_AND_RETURN_LOG(ref != nullptr, "%{public}s AutoRef is nullptr", jsCb->callbackName_.c_str());
209 napi_handle_scope scope = nullptr;
210 napi_open_handle_scope(ref->env_, &scope);
211 CHECK_AND_RETURN_LOG(scope != nullptr, "%{public}s scope is nullptr", jsCb->callbackName_.c_str());
212 ON_SCOPE_EXIT(0) {
213 napi_close_handle_scope(ref->env_, scope);
214 };
215 napi_value jsCallback = nullptr;
216 napi_status napiStatus = napi_get_reference_value(ref->env_, ref->cb_, &jsCallback);
217 CHECK_AND_RETURN_LOG(napiStatus == napi_ok && jsCallback != nullptr,
218 "%{public}s failed to napi_get_reference_value", jsCb->callbackName_.c_str());
219
220 napi_value args[ARRAY_ARG_COUNTS_ONE] = { nullptr };
221 CHECK_AND_BREAK_LOG(napi_create_int64(ref->env_, jsCb->uuid_, &args[INDEX_A]) == napi_ok,
222 "set uuid failed");
223
224 napi_value result = nullptr;
225 napiStatus = napi_call_function(ref->env_, nullptr, jsCallback, ARRAY_ARG_COUNTS_ONE, args, &result);
226 CHECK_AND_RETURN_LOG(napiStatus == napi_ok,
227 "%{public}s failed to napi_call_function", jsCb->callbackName_.c_str());
228 } while (0);
229 }, napi_eprio_immediate);
230 if (ret != napi_ok) {
231 MEDIA_LOGE("Failed to execute libuv work queue");
232 }
233 }
234
SaveCallbackReference(const std::string & name,std::shared_ptr<AutoRef> ref)235 void MediaSourceLoaderCallback::SaveCallbackReference(const std::string &name, std::shared_ptr<AutoRef> ref)
236 {
237 MEDIA_LOGI("Add Callback: %{public}s", name.c_str());
238 std::lock_guard<std::mutex> lock(mutex_);
239 refMap_[name] = ref;
240 }
241
ClearCallbackReference()242 void MediaSourceLoaderCallback::ClearCallbackReference()
243 {
244 MEDIA_LOGI("ClearCallbackReference");
245 std::lock_guard<std::mutex> lock(mutex_);
246 std::map<std::string, std::shared_ptr<AutoRef>> temp;
247 temp.swap(refMap_);
248 MEDIA_LOGI("callback has been clear");
249 if (jsCb_) {
250 jsCb_->isExit_ = true;
251 jsCb_->cond_.notify_all();
252 }
253 }
254 } // namespace Media
255 } // namespace OHOS
256