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 session manager.
15 * Author: zhangjingnan
16 * Create: 2022-7-11
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 "cast_session_manager.h"
25 #include "napi_cast_session_manager_listener.h"
26 #include "napi_cast_session.h"
27 #include "napi_castengine_utils.h"
28 #include "napi_cast_session_manager.h"
29 #include "napi_async_work.h"
30
31 using namespace OHOS::CastEngine::CastEngineClient;
32 using namespace std;
33
34 namespace OHOS {
35 namespace CastEngine {
36 namespace CastEngineClient {
37 DEFINE_CAST_ENGINE_LABEL("Cast-Napi-SessionManager");
38
39 std::shared_ptr<NapiCastSessionManagerListener> NapiCastSessionManager::listener_;
40
41 std::map<std::string, std::pair<NapiCastSessionManager::OnEventHandlerType,
42 NapiCastSessionManager::OffEventHandlerType>>
43 NapiCastSessionManager::eventHandlers_ = {
44 { "serviceDie", { OnServiceDied, OffServiceDie } },
45 { "deviceFound", { OnDeviceFound, OffDeviceFound } },
46 { "sessionCreate", { OnSessionCreated, OffSessionCreated } },
47 { "deviceOffline", { OnDeviceOffline, OffDeviceOffline } }
48 };
49
Init(napi_env env,napi_value exports)50 napi_value NapiCastSessionManager::Init(napi_env env, napi_value exports)
51 {
52 napi_property_descriptor NapiCastSessionManagerDesc[] = {
53 DECLARE_NAPI_FUNCTION("on", OnEvent),
54 DECLARE_NAPI_FUNCTION("off", OffEvent),
55 DECLARE_NAPI_FUNCTION("startDiscovery", StartDiscovery),
56 DECLARE_NAPI_FUNCTION("stopDiscovery", StopDiscovery),
57 DECLARE_NAPI_FUNCTION("setDiscoverable", SetDiscoverable),
58 DECLARE_NAPI_FUNCTION("createCastSession", CreateCastSession),
59 DECLARE_NAPI_FUNCTION("release", Release)
60 };
61
62 napi_status status = napi_define_properties(env, exports,
63 sizeof(NapiCastSessionManagerDesc) / sizeof(napi_property_descriptor), NapiCastSessionManagerDesc);
64 if (status != napi_ok) {
65 CLOGE("define manager properties failed");
66 return GetUndefinedValue(env);
67 }
68 return exports;
69 }
70
StartDiscovery(napi_env env,napi_callback_info info)71 napi_value NapiCastSessionManager::StartDiscovery(napi_env env, napi_callback_info info)
72 {
73 CLOGD("Start to discovery in");
74 struct ConcreteTask : public NapiAsyncTask {
75 int protocolType_;
76 };
77 auto napiAsyntask = std::make_shared<ConcreteTask>();
78 if (napiAsyntask == nullptr) {
79 CLOGE("Create NapiAsyncTask failed");
80 return GetUndefinedValue(env);
81 }
82
83 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
84 constexpr size_t expectedArgc = 1;
85 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
86 NapiErrors::errcode_[ERR_INVALID_PARAM]);
87 napi_valuetype expectedTypes[expectedArgc] = { napi_object };
88 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
89 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
90 NapiErrors::errcode_[ERR_INVALID_PARAM]);
91 int32_t protocolTypeInt;
92 bool isProtocolTypesValid = GetProtocolTypesFromJS(env, argv[0], protocolTypeInt);
93 CHECK_ARGS_RETURN_VOID(napiAsyntask, isProtocolTypesValid, "invalid arguments",
94 NapiErrors::errcode_[ERR_INVALID_PARAM]);
95 napiAsyntask->protocolType_ = protocolTypeInt;
96 };
97 napiAsyntask->GetJSInfo(env, info, inputParser);
98 auto executor = [napiAsyntask]() {
99 int32_t ret = CastSessionManager::GetInstance().StartDiscovery(napiAsyntask->protocolType_);
100 if (ret != CAST_ENGINE_SUCCESS) {
101 if (ret == ERR_NO_PERMISSION) {
102 napiAsyntask->errMessage = "StartDiscovery failed : no permission";
103 } else if (ret == ERR_INVALID_PARAM) {
104 napiAsyntask->errMessage = "StartDiscovery failed : invalid parameters";
105 } else {
106 napiAsyntask->errMessage = "StartDiscovery failed : native server exception";
107 }
108 napiAsyntask->status = napi_generic_failure;
109 napiAsyntask->errCode = NapiErrors::errcode_[ret];
110 }
111 };
112
113 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
114 return NapiAsyncWork::Enqueue(env, napiAsyntask, "StartDiscovery", executor, complete);
115 }
116
StopDiscovery(napi_env env,napi_callback_info info)117 napi_value NapiCastSessionManager::StopDiscovery(napi_env env, napi_callback_info info)
118 {
119 CLOGD("Start to stop discovery in");
120 auto napiAsyntask = std::make_shared<NapiAsyncTask>();
121 if (napiAsyntask == nullptr) {
122 CLOGE("Create NapiAsyncTask failed");
123 return GetUndefinedValue(env);
124 }
125 napiAsyntask->GetJSInfo(env, info);
126
127 auto executor = [napiAsyntask]() {
128 int32_t ret = CastSessionManager::GetInstance().StopDiscovery();
129 if (ret != CAST_ENGINE_SUCCESS) {
130 if (ret == ERR_NO_PERMISSION) {
131 napiAsyntask->errMessage = "StopDiscovery failed : no permission";
132 } else {
133 napiAsyntask->errMessage = "StopDiscovery failed : native server exception";
134 }
135 napiAsyntask->status = napi_generic_failure;
136 napiAsyntask->errCode = NapiErrors::errcode_[ret];
137 }
138 };
139 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
140 return NapiAsyncWork::Enqueue(env, napiAsyntask, "StopDiscovery", executor, complete);
141 }
142
SetDiscoverable(napi_env env,napi_callback_info info)143 napi_value NapiCastSessionManager::SetDiscoverable(napi_env env, napi_callback_info info)
144 {
145 CLOGD("Start to set discoverable in");
146 struct ConcreteTask : public NapiAsyncTask {
147 bool isEnable_;
148 };
149 auto napiAsyntask = std::make_shared<ConcreteTask>();
150 if (napiAsyntask == nullptr) {
151 CLOGE("Create NapiAsyncTask failed");
152 return GetUndefinedValue(env);
153 }
154
155 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
156 constexpr size_t expectedArgc = 1;
157 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
158 NapiErrors::errcode_[ERR_INVALID_PARAM]);
159 napi_valuetype expectedTypes[expectedArgc] = { napi_boolean };
160 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
161 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
162 NapiErrors::errcode_[ERR_INVALID_PARAM]);
163 napiAsyntask->isEnable_ = ParseBool(env, argv[0]);
164 };
165 napiAsyntask->GetJSInfo(env, info, inputParser);
166 auto executor = [napiAsyntask]() {
167 int32_t ret = CastSessionManager::GetInstance().SetDiscoverable(napiAsyntask->isEnable_);
168 if (ret != CAST_ENGINE_SUCCESS) {
169 if (ret == ERR_NO_PERMISSION) {
170 napiAsyntask->errMessage = "SetDiscoverable failed : no permission";
171 } else {
172 napiAsyntask->errMessage = "SetDiscoverable failed : native server exception";
173 }
174 napiAsyntask->status = napi_generic_failure;
175 napiAsyntask->errCode = NapiErrors::errcode_[ret];
176 }
177 };
178
179 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
180 return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetDiscoverable", executor, complete);
181 }
182
CreateCastSession(napi_env env,napi_callback_info info)183 napi_value NapiCastSessionManager::CreateCastSession(napi_env env, napi_callback_info info)
184 {
185 CLOGD("Start to create castSession in");
186 struct ConcreteTask : public NapiAsyncTask {
187 CastSessionProperty property_;
188 std::shared_ptr<ICastSession> session_;
189 };
190 auto napiAsyntask = std::make_shared<ConcreteTask>();
191 if (napiAsyntask == nullptr) {
192 CLOGE("Create NapiAsyncTask failed");
193 return GetUndefinedValue(env);
194 }
195
196 auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) {
197 constexpr size_t expectedArgc = 1;
198 CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments",
199 NapiErrors::errcode_[ERR_INVALID_PARAM]);
200 napi_valuetype expectedTypes[expectedArgc] = { napi_object };
201 bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes);
202 CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments",
203 NapiErrors::errcode_[ERR_INVALID_PARAM]);
204 napiAsyntask->property_ = GetCastSessionPropertyFromJS(env, argv[0]);
205 };
206 napiAsyntask->GetJSInfo(env, info, inputParser);
207 auto executor = [napiAsyntask]() {
208 int32_t ret =
209 CastSessionManager::GetInstance().CreateCastSession(napiAsyntask->property_, napiAsyntask->session_);
210 if (ret != CAST_ENGINE_SUCCESS) {
211 if (ret == ERR_NO_PERMISSION) {
212 napiAsyntask->errMessage = "CreateCastSession failed : no permission";
213 } else if (ret == ERR_INVALID_PARAM) {
214 napiAsyntask->errMessage = "CreateCastSession failed : invalid parameters";
215 } else {
216 napiAsyntask->errMessage = "CreateCastSession failed : native server exception";
217 }
218 napiAsyntask->status = napi_generic_failure;
219 napiAsyntask->errCode = NapiErrors::errcode_[ret];
220 }
221 };
222
223 auto complete = [napiAsyntask](napi_value &output) {
224 napiAsyntask->status =
225 NapiCastSession::CreateNapiCastSession(napiAsyntask->env, napiAsyntask->session_, output);
226 CHECK_STATUS_RETURN_VOID(napiAsyntask, "convert native object to javascript object failed",
227 NapiErrors::errcode_[CAST_ENGINE_ERROR]);
228 };
229 return NapiAsyncWork::Enqueue(env, napiAsyntask, "CreateCastSession", executor, complete);
230 }
231
Release(napi_env env,napi_callback_info info)232 napi_value NapiCastSessionManager::Release(napi_env env, napi_callback_info info)
233 {
234 CLOGD("Start to release in");
235 auto napiAsyntask = std::make_shared<NapiAsyncTask>();
236 if (napiAsyntask == nullptr) {
237 CLOGE("Create NapiAsyncTask failed");
238 return GetUndefinedValue(env);
239 }
240 napiAsyntask->GetJSInfo(env, info);
241
242 auto executor = [napiAsyntask]() {
243 int32_t ret = CastSessionManager::GetInstance().Release();
244 if (ret != CAST_ENGINE_SUCCESS) {
245 if (ret == ERR_NO_PERMISSION) {
246 napiAsyntask->errMessage = "Release failed : no permission";
247 } else {
248 napiAsyntask->errMessage = "Release failed : native server exception";
249 }
250 napiAsyntask->status = napi_generic_failure;
251 napiAsyntask->errCode = NapiErrors::errcode_[ret];
252 }
253 };
254 auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); };
255 return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete);
256 }
257
OnEvent(napi_env env,napi_callback_info info)258 napi_value NapiCastSessionManager::OnEvent(napi_env env, napi_callback_info info)
259 {
260 constexpr size_t expectedArgc = 2;
261 napi_value argv[expectedArgc] = { 0 };
262 napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function };
263 if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) {
264 return GetUndefinedValue(env);
265 }
266
267 std::string eventName = ParseString(env, argv[0]);
268 auto it = eventHandlers_.find(eventName);
269 if (it == eventHandlers_.end()) {
270 CLOGE("event name invalid");
271 return GetUndefinedValue(env);
272 }
273
274 if (RegisterNativeSessionManagerListener() == napi_generic_failure) {
275 return GetUndefinedValue(env);
276 }
277 if (it->second.first(env, argv[1]) != napi_ok) {
278 CLOGE("event name invalid");
279 }
280
281 return GetUndefinedValue(env);
282 }
283
OffEvent(napi_env env,napi_callback_info info)284 napi_value NapiCastSessionManager::OffEvent(napi_env env, napi_callback_info info)
285 {
286 constexpr size_t expectedArgc = 2;
287 napi_value argv[expectedArgc] = { 0 };
288 napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function};
289 if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) {
290 return GetUndefinedValue(env);
291 }
292
293 std::string eventName = ParseString(env, argv[0]);
294 auto it = eventHandlers_.find(eventName);
295 if (it == eventHandlers_.end()) {
296 CLOGE("event name invalid");
297 return GetUndefinedValue(env);
298 }
299 if (it->second.second(env, argv[1]) != napi_ok) {
300 CLOGE("event name invalid");
301 }
302
303 return GetUndefinedValue(env);
304 }
305
OnServiceDied(napi_env env,napi_value callback)306 napi_status NapiCastSessionManager::OnServiceDied(napi_env env, napi_value callback)
307 {
308 if (!listener_) {
309 CLOGE("cast session manager callback is null");
310 return napi_generic_failure;
311 }
312 if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_SERVICE_DIED, callback) != napi_ok) {
313 return napi_generic_failure;
314 }
315 return napi_ok;
316 }
317
OnDeviceFound(napi_env env,napi_value callback)318 napi_status NapiCastSessionManager::OnDeviceFound(napi_env env, napi_value callback)
319 {
320 if (!listener_) {
321 CLOGE("cast session manager callback is null");
322 return napi_generic_failure;
323 }
324 if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_FOUND, callback) != napi_ok) {
325 return napi_generic_failure;
326 }
327 return napi_ok;
328 }
329
OnSessionCreated(napi_env env,napi_value callback)330 napi_status NapiCastSessionManager::OnSessionCreated(napi_env env, napi_value callback)
331 {
332 if (!listener_) {
333 CLOGE("cast session manager callback is null");
334 return napi_generic_failure;
335 }
336 if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_SESSION_CREATE, callback) != napi_ok) {
337 return napi_generic_failure;
338 }
339 return napi_ok;
340 }
341
OnDeviceOffline(napi_env env,napi_value callback)342 napi_status NapiCastSessionManager::OnDeviceOffline(napi_env env, napi_value callback)
343 {
344 if (!listener_) {
345 CLOGE("cast session manager callback is null");
346 return napi_generic_failure;
347 }
348 if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_OFFLINE, callback) != napi_ok) {
349 return napi_generic_failure;
350 }
351 return napi_ok;
352 }
353
OffServiceDie(napi_env env,napi_value callback)354 napi_status NapiCastSessionManager::OffServiceDie(napi_env env, napi_value callback)
355 {
356 if (!listener_) {
357 CLOGE("cast session manager callback is null");
358 return napi_generic_failure;
359 }
360 if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_SERVICE_DIED, callback) != napi_ok) {
361 return napi_generic_failure;
362 }
363 return napi_ok;
364 }
365
OffDeviceFound(napi_env env,napi_value callback)366 napi_status NapiCastSessionManager::OffDeviceFound(napi_env env, napi_value callback)
367 {
368 if (!listener_) {
369 CLOGE("cast session manager callback is null");
370 return napi_generic_failure;
371 }
372 if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_FOUND, callback) != napi_ok) {
373 return napi_generic_failure;
374 }
375 return napi_ok;
376 }
377
OffSessionCreated(napi_env env,napi_value callback)378 napi_status NapiCastSessionManager::OffSessionCreated(napi_env env, napi_value callback)
379 {
380 if (!listener_) {
381 CLOGE("cast session manager callback is null");
382 return napi_generic_failure;
383 }
384 if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_SESSION_CREATE, callback) != napi_ok) {
385 return napi_generic_failure;
386 }
387 return napi_ok;
388 }
389
OffDeviceOffline(napi_env env,napi_value callback)390 napi_status NapiCastSessionManager::OffDeviceOffline(napi_env env, napi_value callback)
391 {
392 if (!listener_) {
393 CLOGE("cast session manager callback is null");
394 return napi_generic_failure;
395 }
396 if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_OFFLINE, callback) != napi_ok) {
397 return napi_generic_failure;
398 }
399 return napi_ok;
400 }
401
RegisterNativeSessionManagerListener()402 napi_status NapiCastSessionManager::RegisterNativeSessionManagerListener()
403 {
404 if (listener_) {
405 return napi_ok;
406 }
407 listener_ = std::make_shared<NapiCastSessionManagerListener>();
408 if (!listener_) {
409 CLOGE("Failed to malloc session manager listener");
410 return napi_generic_failure;
411 }
412 int32_t ret = CastSessionManager::GetInstance().RegisterListener(listener_);
413 if (ret != CAST_ENGINE_SUCCESS) {
414 CLOGE("native register session manager listener failed");
415 return napi_generic_failure;
416 }
417
418 return napi_ok;
419 }
420 } // namespace CastEngineClient
421 } // namespace CastEngine
422 } // namespace OHOS