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