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