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