1 /*
2 * Copyright (C) 2024 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_napi.h"
17 #include "media_log.h"
18 #include "media_dfx.h"
19
20 namespace {
21 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_PLAYER, "MediaSourceNapi"};
22 constexpr uint32_t MAX_MEDIA_STREAM_ARRAY_LENGTH = 10;
23 }
24
25 namespace OHOS {
26 namespace Media {
27 using namespace FunctionName;
28 const std::string CLASS_NAME = "MediaSource";
29 thread_local napi_ref MediaSourceNapi::constructor_ = nullptr;
30
Init(napi_env env,napi_value exports)31 napi_value MediaSourceNapi::Init(napi_env env, napi_value exports)
32 {
33 napi_property_descriptor staticProperty[] = {
34 DECLARE_NAPI_STATIC_FUNCTION("createMediaSourceWithUrl", JsCreateMediaSourceWithUrl),
35 DECLARE_NAPI_STATIC_FUNCTION("createMediaSourceWithStreamData", JsCreateMediaSourceWithStreamData),
36 };
37
38 napi_property_descriptor properties[] = {
39 DECLARE_NAPI_FUNCTION("setMimeType", JsSetMimeType),
40 DECLARE_NAPI_FUNCTION("setMediaResourceLoaderDelegate", JsSetMediaResourceLoaderDelegate),
41 };
42
43 napi_value constructor = nullptr;
44 napi_status status = napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr,
45 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
46 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define AVPlayer class");
47
48 status = napi_create_reference(env, constructor, 1, &constructor_);
49 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to create reference of constructor");
50
51 status = napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor);
52 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to set constructor");
53
54 status = napi_define_properties(env, exports, sizeof(staticProperty) / sizeof(staticProperty[0]), staticProperty);
55 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "Failed to define static function");
56 return exports;
57 }
58
GetMediaSource(napi_env env,napi_value jsMediaSource)59 std::shared_ptr<AVMediaSourceTmp> MediaSourceNapi::GetMediaSource(napi_env env, napi_value jsMediaSource)
60 {
61 MediaSourceNapi *mediaSource = nullptr;
62 napi_status status = napi_unwrap(env, jsMediaSource, reinterpret_cast<void **>(&mediaSource));
63 CHECK_AND_RETURN_RET_LOG(status == napi_ok && mediaSource != nullptr, nullptr, "failed to napi_unwrap");
64
65 return mediaSource->mediaSource_;
66 }
67
GetSourceLoader(napi_env env,napi_value jsMediaSource)68 std::shared_ptr<MediaSourceLoaderCallback> MediaSourceNapi::GetSourceLoader(napi_env env, napi_value jsMediaSource)
69 {
70 MediaSourceNapi *mediaSource = nullptr;
71 napi_status status = napi_unwrap(env, jsMediaSource, reinterpret_cast<void **>(&mediaSource));
72 CHECK_AND_RETURN_RET_LOG(status == napi_ok && mediaSource != nullptr, nullptr, "failed to napi_unwrap");
73
74 return mediaSource->mediaSourceLoaderCb_;
75 }
76
Constructor(napi_env env,napi_callback_info info)77 napi_value MediaSourceNapi::Constructor(napi_env env, napi_callback_info info)
78 {
79 napi_value result = nullptr;
80 napi_get_undefined(env, &result);
81
82 size_t argCount = 0;
83 napi_value jsThis = nullptr;
84 napi_status status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr);
85 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "failed to napi_get_cb_info");
86
87 MediaSourceNapi *jsMediaSource = new(std::nothrow) MediaSourceNapi();
88 CHECK_AND_RETURN_RET_LOG(jsMediaSource != nullptr, result, "failed to new MediaSourceNapi");
89
90 jsMediaSource->env_ = env;
91 jsMediaSource->mediaSource_ = std::make_shared<AVMediaSourceTmp>();
92 if (jsMediaSource->mediaSource_ == nullptr) {
93 delete jsMediaSource;
94 MEDIA_LOGE("Failed to Create MediaSource");
95 return result;
96 }
97
98 status = napi_wrap(env, jsThis, reinterpret_cast<void *>(jsMediaSource),
99 MediaSourceNapi::Destructor, nullptr, nullptr);
100 if (status != napi_ok) {
101 delete jsMediaSource;
102 MEDIA_LOGE("Failed to wrap native instance");
103 return result;
104 }
105
106 MEDIA_LOGI("0x%{public}06" PRIXPTR " Constructor success", FAKE_POINTER(jsMediaSource));
107 return jsThis;
108 }
109
Destructor(napi_env env,void * nativeObject,void * finalize)110 void MediaSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
111 {
112 (void)env;
113 (void)finalize;
114 if (nativeObject != nullptr) {
115 MediaSourceNapi *jsMediaSource = reinterpret_cast<MediaSourceNapi *>(nativeObject);
116 jsMediaSource->mediaSource_ = nullptr;
117 if (jsMediaSource->mediaSourceLoaderCb_ != nullptr) {
118 jsMediaSource->mediaSourceLoaderCb_->ClearCallbackReference();
119 jsMediaSource->mediaSourceLoaderCb_ = nullptr;
120 }
121 delete jsMediaSource;
122 }
123 MEDIA_LOGI("Destructor success");
124 }
125
JsCreateMediaSourceWithUrl(napi_env env,napi_callback_info info)126 napi_value MediaSourceNapi::JsCreateMediaSourceWithUrl(napi_env env, napi_callback_info info)
127 {
128 MEDIA_LOGD("JsCreateMediaSourceWithUrl In");
129 size_t argCount = 2;
130 napi_value args[2] = { nullptr };
131 napi_value jsMediaSource = nullptr;
132 napi_get_undefined(env, &jsMediaSource);
133 napi_status status = napi_get_cb_info(env, info, &argCount, args, nullptr, nullptr);
134 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "failed to napi_get_cb_info");
135
136 napi_valuetype valueType = napi_undefined;
137 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
138 return nullptr;
139 }
140
141 napi_value constructor = nullptr;
142 napi_status ret = napi_get_reference_value(env, constructor_, &constructor);
143 if (ret != napi_ok || constructor == nullptr) {
144 return nullptr;
145 }
146 napi_new_instance(env, constructor, 0, nullptr, &jsMediaSource);
147
148 std::shared_ptr<AVMediaSourceTmp> mediaSource = GetMediaSource(env, jsMediaSource);
149 if (mediaSource == nullptr) {
150 MEDIA_LOGE("JsCreateMediaSourceWithUrl GetMediaSource fail");
151 return nullptr;
152 }
153 mediaSource->url = CommonNapi::GetStringArgument(env, args[0]);
154 MEDIA_LOGE("JsCreateMediaSourceWithUrl get map");
155 (void)CommonNapi::GetPropertyMap(env, args[1], mediaSource->header);
156 return jsMediaSource;
157 }
158
JsCreateMediaSourceWithStreamData(napi_env env,napi_callback_info info)159 napi_value MediaSourceNapi::JsCreateMediaSourceWithStreamData(napi_env env, napi_callback_info info)
160 {
161 MEDIA_LOGD("JsCreateMediaSourceWithStreamData In");
162 size_t argCount = 1;
163 napi_value args[1] = { nullptr };
164 napi_value jsMediaSource = nullptr;
165 napi_get_undefined(env, &jsMediaSource);
166 napi_status status = napi_get_cb_info(env, info, &argCount, args, nullptr, nullptr);
167 CHECK_AND_RETURN_RET_LOG(status == napi_ok, nullptr, "failed to napi_get_cb_info");
168
169 bool isArray = false;
170 if (argCount < 1 || napi_is_array(env, args[0], &isArray) != napi_ok || !isArray) {
171 return nullptr;
172 }
173
174 uint32_t length = 0;
175 if (napi_get_array_length(env, args[0], &length) != napi_ok || length == 0) {
176 return nullptr;
177 }
178 CHECK_AND_RETURN_RET_LOG(length <= MAX_MEDIA_STREAM_ARRAY_LENGTH, nullptr, "length Array<MediaStream> is too long");
179
180 napi_value constructor = nullptr;
181 napi_status ret = napi_get_reference_value(env, constructor_, &constructor);
182 if (ret != napi_ok || constructor == nullptr) {
183 return nullptr;
184 }
185 napi_new_instance(env, constructor, 0, nullptr, &jsMediaSource);
186
187 std::shared_ptr<AVMediaSourceTmp> mediaSource = GetMediaSource(env, jsMediaSource);
188 if (mediaSource == nullptr) {
189 MEDIA_LOGE("JsCreateMediaSourceWithStreamData GetMediaSource fail");
190 return nullptr;
191 }
192
193 for (uint32_t i = 0; i < length; i++) {
194 napi_value element;
195 AVPlayMediaStreamTmp mediaStream;
196 status = napi_get_element(env, args[0], i, &element);
197 if (status != napi_ok) {
198 return nullptr;
199 }
200 if (!CommonNapi::GetPlayMediaStreamData(env, element, mediaStream)) {
201 return nullptr;
202 }
203 MEDIA_LOGI("url=%{private}s width=%{public}d height=%{public}d bitrate=%{public}d",
204 mediaStream.url.c_str(),
205 mediaStream.width,
206 mediaStream.height,
207 mediaStream.bitrate);
208 mediaSource->AddAVPlayMediaStreamTmp(mediaStream);
209 }
210 MEDIA_LOGD("JsCreateMediaSourceWithStreamData get mediaStreamVec length=%{public}u", length);
211 return jsMediaSource;
212 }
213
JsSetMimeType(napi_env env,napi_callback_info info)214 napi_value MediaSourceNapi::JsSetMimeType(napi_env env, napi_callback_info info)
215 {
216 MEDIA_LOGI("JsSetMimeType In");
217 napi_value undefinedResult = nullptr;
218 napi_get_undefined(env, &undefinedResult);
219 size_t argCount = 1;
220 napi_value args[1] = {nullptr};
221 napi_value jsThis = nullptr;
222 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
223 CHECK_AND_RETURN_RET_LOG(status == napi_ok, undefinedResult, "failed to napi_get_cb_info");
224
225 napi_valuetype valueType = napi_undefined;
226 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_string) {
227 return undefinedResult;
228 }
229
230 std::string mimeType = CommonNapi::GetStringArgument(env, args[0]);
231 std::shared_ptr<AVMediaSourceTmp> mediaSource = GetMediaSource(env, jsThis);
232
233 if (mediaSource == nullptr) {
234 MEDIA_LOGE("Fail to get mediaSource instance.");
235 return undefinedResult;
236 }
237 if (mimeType.empty()) {
238 MEDIA_LOGE("MimeType is empty.");
239 return undefinedResult;
240 }
241
242 mediaSource->SetMimeType(mimeType);
243
244 return undefinedResult;
245 }
246
JsSetMediaResourceLoaderDelegate(napi_env env,napi_callback_info info)247 napi_value MediaSourceNapi::JsSetMediaResourceLoaderDelegate(napi_env env, napi_callback_info info)
248 {
249 MediaTrace trace("MediaSourceNapi::SetMediaResourceLoaderDelegate");
250 napi_value result = nullptr;
251 napi_get_undefined(env, &result);
252 MEDIA_LOGI("JsSetMediaResourceLoaderDelegate In");
253
254 napi_value args[1] = { nullptr };
255 size_t argCount = 1;
256
257 napi_value jsThis = nullptr;
258 napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr);
259 CHECK_AND_RETURN_RET_LOG(status == napi_ok && jsThis != nullptr, nullptr, "failed to napi_get_cb_info");
260
261 MediaSourceNapi *mediaSource = nullptr;
262 status = napi_unwrap(env, jsThis, reinterpret_cast<void **>(&mediaSource));
263 CHECK_AND_RETURN_RET_LOG(status == napi_ok && mediaSource != nullptr, nullptr, "failed to napi_unwrap");
264
265 napi_valuetype valueType = napi_undefined;
266 if (argCount < 1 || napi_typeof(env, args[0], &valueType) != napi_ok || valueType != napi_object) {
267 MEDIA_LOGE("SetMediaResourceLoaderDelegate invalid parameters");
268 return result;
269 }
270
271 mediaSource->mediaSourceLoaderCb_ = std::make_shared<MediaSourceLoaderCallback>(env);
272 CHECK_AND_RETURN_RET_LOG(mediaSource->mediaSourceLoaderCb_ != nullptr, result, "Cb_ is nullptr");
273
274 napi_value callback = nullptr;
275 napi_ref ref = nullptr;
276 napi_get_named_property(env, args[0], SOURCE_OPEN.c_str(), &callback);
277 status = napi_create_reference(env, callback, 1, &ref);
278 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create open reference!");
279 std::shared_ptr<AutoRef> autoRef = std::make_shared<AutoRef>(env, ref);
280 CHECK_AND_RETURN_RET_LOG(autoRef != nullptr, result, "open is nullptr");
281 mediaSource->mediaSourceLoaderCb_->SaveCallbackReference(SOURCE_OPEN, autoRef);
282
283 napi_get_named_property(env, args[0], SOURCE_READ.c_str(), &callback);
284 status = napi_create_reference(env, callback, 1, &ref);
285 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create read reference!");
286 autoRef = std::make_shared<AutoRef>(env, ref);
287 CHECK_AND_RETURN_RET_LOG(autoRef != nullptr, result, "read is nullptr");
288 mediaSource->mediaSourceLoaderCb_->SaveCallbackReference(SOURCE_READ, autoRef);
289
290 napi_get_named_property(env, args[0], SOURCE_CLOSE.c_str(), &callback);
291 status = napi_create_reference(env, callback, 1, &ref);
292 CHECK_AND_RETURN_RET_LOG(status == napi_ok && ref != nullptr, result, "failed to create close reference!");
293 autoRef = std::make_shared<AutoRef>(env, ref);
294 CHECK_AND_RETURN_RET_LOG(autoRef != nullptr, result, "close is nullptr");
295 mediaSource->mediaSourceLoaderCb_->SaveCallbackReference(SOURCE_CLOSE, autoRef);
296 MEDIA_LOGI("JsSetMediaResourceLoaderDelegate Out");
297 return result;
298 }
299 } // Media
300 } // OHOS