• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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