1 /*
2 * Copyright (C) 2023-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 * Description: supply napi interface realization for cast mirror player.
15 * Author: zhangjingnan
16 * Create: 2023-5-27
17 */
18
19 #include <memory>
20 #include "napi/native_api.h"
21 #include "napi/native_node_api.h"
22 #include "cast_engine_log.h"
23 #include "cast_engine_common.h"
24 #include "oh_remote_control_event.h"
25 #include "i_mirror_player.h"
26 #include "napi_castengine_utils.h"
27 #include "napi_mirror_player.h"
28 #include "napi_async_work.h"
29
30 using namespace OHOS::CastEngine::CastEngineClient;
31 using namespace std;
32
33 namespace OHOS {
34 namespace CastEngine {
35 namespace CastEngineClient {
36 DEFINE_CAST_ENGINE_LABEL("Cast-Napi-MirrorPlayer");
37
38 thread_local napi_ref NapiMirrorPlayer::consRef_ = nullptr;
39
DefineMirrorPlayerJSClass(napi_env env)40 void NapiMirrorPlayer::DefineMirrorPlayerJSClass(napi_env env)
41 {
42 napi_property_descriptor NapiMirrorPlayerDesc[] = {
43 DECLARE_NAPI_FUNCTION("play", Play),
44 DECLARE_NAPI_FUNCTION("pause", Pause),
45 DECLARE_NAPI_FUNCTION("setAppInfo", SetAppInfo),
46 DECLARE_NAPI_FUNCTION("setSurface", SetSurface),
47 DECLARE_NAPI_FUNCTION("release", Release),
48 DECLARE_NAPI_FUNCTION("resizeVirtualScreen", ResizeVirtualScreen)
49 };
50
51 napi_value mirrorPlayer = nullptr;
52 constexpr int initialRefCount = 1;
53 napi_status status = napi_define_class(env, "mirrorPlayer", NAPI_AUTO_LENGTH, NapiMirrorPlayerConstructor, nullptr,
54 sizeof(NapiMirrorPlayerDesc) / sizeof(NapiMirrorPlayerDesc[0]), NapiMirrorPlayerDesc, &mirrorPlayer);
55 if (status != napi_ok) {
56 CLOGE("napi_define_class failed");
57 return;
58 }
59 status = napi_create_reference(env, mirrorPlayer, initialRefCount, &consRef_);
60 if (status != napi_ok) {
61 CLOGE("DefineMirrorPlayerJSClass napi_create_reference failed");
62 }
63 }
64
NapiMirrorPlayerConstructor(napi_env env,napi_callback_info info)65 napi_value NapiMirrorPlayer::NapiMirrorPlayerConstructor(napi_env env, napi_callback_info info)
66 {
67 CLOGD("NapiMirrorPlayer start to construct in");
68 napi_value thisVar = nullptr;
69 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
70 CLOGD("NapiMirrorPlayer construct successfully");
71 return thisVar;
72 }
73
CreateNapiMirrorPlayer(napi_env env,shared_ptr<IMirrorPlayer> player,napi_value & out)74 napi_status NapiMirrorPlayer::CreateNapiMirrorPlayer(napi_env env, shared_ptr<IMirrorPlayer> player, napi_value &out)
75 {
76 CLOGD("Start to create napiMirrorPlayer in");
77 napi_value result = nullptr;
78 napi_value constructor = nullptr;
79 if (consRef_ == nullptr || player == nullptr) {
80 CLOGE("CreateNapiMirrorPlayer input is null");
81 return napi_generic_failure;
82 }
83 napi_status status = napi_get_reference_value(env, consRef_, &constructor);
84 if (status != napi_ok || constructor == nullptr) {
85 CLOGE("CreateNapiMirrorPlayer napi_get_reference_value failed");
86 return napi_generic_failure;
87 }
88
89 constexpr size_t argc = 0;
90 status = napi_new_instance(env, constructor, argc, nullptr, &result);
91 if (status != napi_ok) {
92 CLOGE("CreateNapiMirrorPlayer napi_new_instance failed");
93 return napi_generic_failure;
94 }
95
96 NapiMirrorPlayer *napiMirrorPlayer = new NapiMirrorPlayer(player);
97 if (napiMirrorPlayer == nullptr) {
98 CLOGE("NapiMirrorPlayer is nullptr");
99 return napi_generic_failure;
100 }
101 auto finalize = [](napi_env env, void *data, void *hint) {
102 NapiMirrorPlayer *player = reinterpret_cast<NapiMirrorPlayer *>(data);
103 if (player != nullptr) {
104 CLOGI("Session deconstructed");
105 delete player;
106 player = nullptr;
107 }
108 };
109 if (napi_wrap(env, result, napiMirrorPlayer, finalize, nullptr, nullptr) != napi_ok) {
110 CLOGE("CreateNapiMirrorPlayer napi_wrap failed");
111 delete napiMirrorPlayer;
112 napiMirrorPlayer = nullptr;
113 return napi_generic_failure;
114 }
115 out = result;
116 CLOGD("Create napiMirrorPlayer successfully");
117 return napi_ok;
118 }
119
Play(napi_env env,napi_callback_info info)120 napi_value NapiMirrorPlayer::Play(napi_env env, napi_callback_info info)
121 {
122 CLOGD("Start to play in");
123 struct ConcreteTask : public NapiAsyncTask {
124 string deviceId_;
125 };
126 auto napiAsyntask = std::make_shared<ConcreteTask>();
127 if (napiAsyntask == nullptr) {
128 CLOGE("Create NapiAsyncTask failed");
129 return GetUndefinedValue(env);
130 }
131
132 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
133 constexpr size_t expectedArgc = 1;
134 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
135 NapiErrors::errcode_[ERR_INVALID_PARAM]);
136 napi_valuetype expectedTypes[expectedArgc] = { napi_string };
137 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
138 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
139 NapiErrors::errcode_[ERR_INVALID_PARAM]);
140 napiAsyntask->deviceId_ = ParseString(env, argv[0]);
141 };
142 napiAsyntask->GetJSInfo(env, info, inputParser);
143 auto executor = [napiAsyntask]() {
144 auto *napiPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
145 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null",
146 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
147 shared_ptr<IMirrorPlayer> mirrorPlayer = napiPlayer->GetMirrorPlayer();
148 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
149 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
150 int32_t ret = mirrorPlayer->Play(napiAsyntask->deviceId_);
151 if (ret != CAST_ENGINE_SUCCESS) {
152 if (ret == ERR_NO_PERMISSION) {
153 napiAsyntask->errMessage = "Play failed : no permission";
154 } else {
155 napiAsyntask->errMessage = "Play failed : native server exception";
156 }
157 napiAsyntask->status = napi_generic_failure;
158 napiAsyntask->errCode = NapiErrors::errcode_[ret];
159 }
160 };
161
162 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
163 return NapiAsyncWork::Enqueue(env, napiAsyntask, "Play", executor, complete);
164 }
165
Pause(napi_env env,napi_callback_info info)166 napi_value NapiMirrorPlayer::Pause(napi_env env, napi_callback_info info)
167 {
168 CLOGD("Start to pause in");
169 struct ConcreteTask : public NapiAsyncTask {
170 string deviceId_;
171 };
172 auto napiAsyntask = std::make_shared<ConcreteTask>();
173 if (napiAsyntask == nullptr) {
174 CLOGE("Create NapiAsyncTask failed");
175 return GetUndefinedValue(env);
176 }
177
178 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
179 constexpr size_t expectedArgc = 1;
180 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
181 NapiErrors::errcode_[ERR_INVALID_PARAM]);
182 napi_valuetype expectedTypes[expectedArgc] = { napi_string };
183 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
184 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
185 NapiErrors::errcode_[ERR_INVALID_PARAM]);
186 napiAsyntask->deviceId_ = ParseString(env, argv[0]);
187 };
188 napiAsyntask->GetJSInfo(env, info, inputParser);
189 auto executor = [napiAsyntask]() {
190 auto *napiPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
191 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null",
192 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
193 shared_ptr<IMirrorPlayer> mirrorPlayer = napiPlayer->GetMirrorPlayer();
194 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
195 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
196 int32_t ret = mirrorPlayer->Pause(napiAsyntask->deviceId_);
197 if (ret != CAST_ENGINE_SUCCESS) {
198 if (ret == ERR_NO_PERMISSION) {
199 napiAsyntask->errMessage = "Pause failed : no permission";
200 } else {
201 napiAsyntask->errMessage = "Pause failed : native server exception";
202 }
203 napiAsyntask->status = napi_generic_failure;
204 napiAsyntask->errCode = NapiErrors::errcode_[ret];
205 }
206 };
207
208 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
209 return NapiAsyncWork::Enqueue(env, napiAsyntask, "Pause", executor, complete);
210 }
211
SetSurface(napi_env env,napi_callback_info info)212 napi_value NapiMirrorPlayer::SetSurface(napi_env env, napi_callback_info info)
213 {
214 CLOGD("Start to set surface in");
215 struct ConcreteTask : public NapiAsyncTask {
216 string surfaceId_;
217 };
218 auto napiAsyntask = std::make_shared<ConcreteTask>();
219 if (napiAsyntask == nullptr) {
220 CLOGE("Create NapiAsyncTask failed");
221 return GetUndefinedValue(env);
222 }
223
224 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
225 constexpr size_t expectedArgc = 1;
226 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
227 NapiErrors::errcode_[ERR_INVALID_PARAM]);
228 napi_valuetype expectedTypes[expectedArgc] = { napi_string };
229 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
230 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
231 NapiErrors::errcode_[ERR_INVALID_PARAM]);
232 napiAsyntask->surfaceId_ = ParseString(env, argv[0]);
233 };
234 napiAsyntask->GetJSInfo(env, info, inputParser);
235 auto executor = [napiAsyntask]() {
236 auto *napiPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
237 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null",
238 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
239 shared_ptr<IMirrorPlayer> mirrorPlayer = napiPlayer->GetMirrorPlayer();
240 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
241 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
242 int32_t ret = mirrorPlayer->SetSurface(napiAsyntask->surfaceId_);
243 if (ret != CAST_ENGINE_SUCCESS) {
244 if (ret == ERR_NO_PERMISSION) {
245 napiAsyntask->errMessage = "SetSurface failed : no permission";
246 } else {
247 napiAsyntask->errMessage = "SetSurface failed : native server exception";
248 }
249 napiAsyntask->status = napi_generic_failure;
250 napiAsyntask->errCode = NapiErrors::errcode_[ret];
251 }
252 };
253
254 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
255 return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetSurface", executor, complete);
256 }
257
SetAppInfo(napi_env env,napi_callback_info info)258 napi_value NapiMirrorPlayer::SetAppInfo(napi_env env, napi_callback_info info)
259 {
260 CLOGD("Start to set appInfo in");
261 struct ConcreteTask : public NapiAsyncTask {
262 int32_t appUid;
263 uint32_t appTokenId;
264 int32_t appPid;
265 };
266 auto napiAsyntask = std::make_shared<ConcreteTask>();
267 if (napiAsyntask == nullptr) {
268 CLOGE("Create NapiAsyncTask failed");
269 return GetUndefinedValue(env);
270 }
271
272 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
273 constexpr size_t expectedArgc = 3;
274 napi_valuetype expectedTypes[expectedArgc] = { napi_number, napi_number, napi_number};
275 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
276 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
277 NapiErrors::errcode_[ERR_INVALID_PARAM]);
278 napiAsyntask->appUid = ParseInt32(env, argv[0]);
279 napiAsyntask->appTokenId = static_cast<uint32_t>(ParseInt32(env, argv[1]));
280 napiAsyntask->appPid = ParseInt32(env, argv[2]);
281 };
282
283 napiAsyntask->GetJSInfo(env, info, inputParser);
284 auto executor = [napiAsyntask]() {
285 auto *napiPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
286 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null",
287 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
288 shared_ptr<IMirrorPlayer> mirrorPlayer = napiPlayer->GetMirrorPlayer();
289 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
290 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
291 CLOGI("SetAppInfo in");
292 int32_t ret = mirrorPlayer->SetAppInfo({napiAsyntask->appUid, napiAsyntask->appTokenId, napiAsyntask->appPid});
293 CLOGI("SetAppInfo out");
294 if (ret != CAST_ENGINE_SUCCESS) {
295 if (ret == ERR_NO_PERMISSION) {
296 napiAsyntask->errMessage = "SetAppInfo failed : no permission";
297 } else {
298 napiAsyntask->errMessage = "SetAppInfo failed : native server exception";
299 }
300 napiAsyntask->status = napi_generic_failure;
301 napiAsyntask->errCode = NapiErrors::errcode_[ret];
302 }
303 };
304 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
305 return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetAppInfo", executor, complete);
306 }
307
Release(napi_env env,napi_callback_info info)308 napi_value NapiMirrorPlayer::Release(napi_env env, napi_callback_info info)
309 {
310 CLOGD("Start to release in");
311 auto napiAsyntask = std::make_shared<NapiAsyncTask>();
312 if (napiAsyntask == nullptr) {
313 CLOGE("Create NapiAsyncTask failed");
314 return GetUndefinedValue(env);
315 }
316 napiAsyntask->GetJSInfo(env, info);
317
318 auto executor = [napiAsyntask]() {
319 auto *napiPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
320 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null",
321 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
322 shared_ptr<IMirrorPlayer> mirrorPlayer = napiPlayer->GetMirrorPlayer();
323 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
324 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
325 int32_t ret = mirrorPlayer->Release();
326 if (ret == CAST_ENGINE_SUCCESS) {
327 napiPlayer->Reset();
328 } else if (ret == ERR_NO_PERMISSION) {
329 napiAsyntask->errMessage = "Release failed : no permission";
330 napiAsyntask->status = napi_generic_failure;
331 napiAsyntask->errCode = NapiErrors::errcode_[ret];
332 } else {
333 napiAsyntask->errMessage = "Release failed : native server exception";
334 napiAsyntask->status = napi_generic_failure;
335 napiAsyntask->errCode = NapiErrors::errcode_[ret];
336 }
337 };
338
339 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
340 return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete);
341 }
342
ResizeVirtualScreen(napi_env env,napi_callback_info info)343 napi_value NapiMirrorPlayer::ResizeVirtualScreen(napi_env env, napi_callback_info info)
344 {
345 struct ConcreteTask : public NapiAsyncTask {
346 uint32_t width_;
347 uint32_t height_;
348 };
349 auto napiAsyntask = std::make_shared<ConcreteTask>();
350 if (napiAsyntask == nullptr) {
351 CLOGE("Create NapiAsyncTask failed");
352 return GetUndefinedValue(env);
353 }
354
355 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
356 constexpr size_t expectedArgc = 2;
357 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
358 NapiErrors::errcode_[ERR_INVALID_PARAM]);
359 napi_valuetype expectedTypes[expectedArgc] = { napi_number, napi_number };
360 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
361 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
362 NapiErrors::errcode_[ERR_INVALID_PARAM]);
363 napiAsyntask->width_ = ParseUint32(env, argv[0]);
364 napiAsyntask->height_ = ParseUint32(env, argv[1]);
365 };
366 napiAsyntask->GetJSInfo(env, info, inputParser);
367 auto executor = [napiAsyntask]() {
368 auto *napiMirrorPlayer = reinterpret_cast<NapiMirrorPlayer *>(napiAsyntask->native);
369 CHECK_ARGS_RETURN_VOID(napiAsyntask, napiMirrorPlayer != nullptr, "napiMirrorPlayer is null",
370 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
371 std::shared_ptr<IMirrorPlayer> mirrorPlayer = napiMirrorPlayer->GetMirrorPlayer();
372 CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null",
373 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
374 int32_t ret = mirrorPlayer->ResizeVirtualScreen(napiAsyntask->width_, napiAsyntask->height_);
375 if (ret != CAST_ENGINE_SUCCESS) {
376 if (ret == ERR_NO_PERMISSION) {
377 napiAsyntask->errMessage = "ResizeVirtualScreen failed : no permission";
378 } else if (ret == ERR_INVALID_PARAM) {
379 napiAsyntask->errMessage = "ResizeVirtualScreen failed : invalid parameters";
380 } else {
381 napiAsyntask->errMessage = "ResizeVirtualScreen failed : native server exception";
382 }
383 napiAsyntask->status = napi_generic_failure;
384 napiAsyntask->errCode = NapiErrors::errcode_[ret];
385 }
386 };
387
388 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
389 return NapiAsyncWork::Enqueue(env, napiAsyntask, "ResizeVirtualScreen", executor, complete);
390 }
391 } // namespace CastEngineClient
392 } // namespace CastEngine
393 } // namespace OHOS