• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "key_event.h"
17 #include "napi_async_work.h"
18 #include "napi_avcontroller_callback.h"
19 #include "napi_avsession_controller.h"
20 #include "napi_control_command.h"
21 #include "napi_meta_data.h"
22 #include "napi_playback_state.h"
23 #include "napi_utils.h"
24 #include "want_agent.h"
25 #include "avsession_errors.h"
26 #include "avsession_trace.h"
27 #include "napi_avsession_manager.h"
28 
29 namespace OHOS::AVSession {
30 static __thread napi_ref AVControllerConstructorRef = nullptr;
31 std::map<std::string, std::pair<NapiAVSessionController::OnEventHandlerType,
32     NapiAVSessionController::OffEventHandlerType>> NapiAVSessionController::EventHandlers_ = {
33     { "sessionDestroy", { OnSessionDestroy, OffSessionDestroy } },
34     { "metadataChange", { OnMetaDataChange, OffMetaDataChange } },
35     { "playbackStateChange", { OnPlaybackStateChange, OffPlaybackStateChange } },
36     { "activeStateChange", { OnActiveStateChange, OffActiveStateChange } },
37     { "validCommandChange", { OnValidCommandChange, OffValidCommandChange } },
38     { "outputDeviceChange", { OnOutputDeviceChange, OffOutputDeviceChange } },
39 };
40 
NapiAVSessionController()41 NapiAVSessionController::NapiAVSessionController()
42 {
43     SLOGI("construct");
44 }
45 
~NapiAVSessionController()46 NapiAVSessionController::~NapiAVSessionController()
47 {
48     SLOGI("destroy");
49 }
50 
Init(napi_env env,napi_value exports)51 napi_value NapiAVSessionController::Init(napi_env env, napi_value exports)
52 {
53     napi_property_descriptor descriptors[] = {
54         DECLARE_NAPI_FUNCTION("on", OnEvent),
55         DECLARE_NAPI_FUNCTION("off", OffEvent),
56         DECLARE_NAPI_FUNCTION("getAVPlaybackState", GetAVPlaybackState),
57         DECLARE_NAPI_FUNCTION("getAVMetadata", GetAVMetaData),
58         DECLARE_NAPI_FUNCTION("getOutputDevice", GetOutputDevice),
59         DECLARE_NAPI_FUNCTION("sendAVKeyEvent", SendAVKeyEvent),
60         DECLARE_NAPI_FUNCTION("getLaunchAbility", GetLaunchAbility),
61         DECLARE_NAPI_FUNCTION("getRealPlaybackPositionSync", GetRealPlaybackPositionSync),
62         DECLARE_NAPI_FUNCTION("isActive", IsSessionActive),
63         DECLARE_NAPI_FUNCTION("destroy", Destroy),
64         DECLARE_NAPI_FUNCTION("getValidCommands", GetValidCommands),
65         DECLARE_NAPI_FUNCTION("sendControlCommand", SendControlCommand),
66     };
67 
68     auto property_count = sizeof(descriptors) / sizeof(napi_property_descriptor);
69     napi_value constructor{};
70     auto status = napi_define_class(env, "AVSessionController", NAPI_AUTO_LENGTH, ConstructorCallback, nullptr,
71         property_count, descriptors, &constructor);
72     if (status != napi_ok) {
73         SLOGE("define class failed");
74         return NapiUtils::GetUndefinedValue(env);
75     }
76     napi_create_reference(env, constructor, 1, &AVControllerConstructorRef);
77     return exports;
78 }
79 
ConstructorCallback(napi_env env,napi_callback_info info)80 napi_value NapiAVSessionController::ConstructorCallback(napi_env env, napi_callback_info info)
81 {
82     napi_value self;
83     NAPI_CALL_BASE(env, napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr), nullptr);
84 
85     auto finalize = [](napi_env env, void* data, void* hint) {
86         auto* napiController = reinterpret_cast<NapiAVSessionController*>(data);
87         napi_delete_reference(env, napiController->wrapperRef_);
88         delete napiController;
89     };
90 
91     auto* napiController = new(std::nothrow) NapiAVSessionController();
92     if (napiController == nullptr) {
93         SLOGE("no memory");
94         return nullptr;
95     }
96     if (napi_wrap(env, self, static_cast<void*>(napiController), finalize, nullptr,
97                   &(napiController->wrapperRef_)) != napi_ok) {
98         SLOGE("wrap failed");
99         return nullptr;
100     }
101     return self;
102 }
103 
NewInstance(napi_env env,std::shared_ptr<AVSessionController> & nativeController,napi_value & out)104 napi_status NapiAVSessionController::NewInstance(napi_env env, std::shared_ptr<AVSessionController>& nativeController,
105     napi_value& out)
106 {
107     napi_value constructor{};
108     NAPI_CALL_BASE(env, napi_get_reference_value(env, AVControllerConstructorRef, &constructor), napi_generic_failure);
109     napi_value instance{};
110     NAPI_CALL_BASE(env, napi_new_instance(env, constructor, 0, nullptr, &instance), napi_generic_failure);
111     NapiAVSessionController* napiController{};
112     NAPI_CALL_BASE(env, napi_unwrap(env, instance, reinterpret_cast<void**>(&napiController)), napi_generic_failure);
113     napiController->controller_ = std::move(nativeController);
114     napiController->sessionId_ = napiController->controller_->GetSessionId();
115 
116     napi_value property {};
117     auto status = NapiUtils::SetValue(env, napiController->sessionId_, property);
118     CHECK_RETURN(status == napi_ok, "create object failed", napi_generic_failure);
119     NAPI_CALL_BASE(env, napi_set_named_property(env, instance, "sessionId", property), napi_generic_failure);
120 
121     out = instance;
122     return napi_ok;
123 }
124 
GetAVPlaybackState(napi_env env,napi_callback_info info)125 napi_value NapiAVSessionController::GetAVPlaybackState(napi_env env, napi_callback_info info)
126 {
127     struct ConcreteContext : public ContextBase {
128         AVPlaybackState state;
129     };
130     auto context = std::make_shared<ConcreteContext>();
131     context->GetCbInfo(env, info);
132 
133     auto executor = [context]() {
134         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
135         if (napiController->controller_ == nullptr) {
136             SLOGE("GetAVPlaybackState failed : controller is nullptr");
137             context->status = napi_generic_failure;
138             context->errMessage = "GetAVPlaybackState failed : controller is nullptr";
139             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
140             return;
141         }
142         int32_t ret = napiController->controller_->GetAVPlaybackState(context->state);
143         if (ret != AVSESSION_SUCCESS) {
144             if (ret == ERR_SESSION_NOT_EXIST) {
145                 context->errMessage = "GetAVPlaybackState failed : native session not exist";
146             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
147                 context->errMessage = "GetAVPlaybackState failed : native controller not exist";
148             } else {
149                 context->errMessage = "GetAVPlaybackState failed : native server exception";
150             }
151             SLOGE("controller GetAVPlaybackState failed:%{public}d", ret);
152             context->status = napi_generic_failure;
153             context->errCode = NapiAVSessionManager::errcode_[ret];
154         }
155     };
156 
157     auto complete = [env, context](napi_value& output) {
158         context->status = NapiPlaybackState::SetValue(env, context->state, output);
159         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
160             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
161     };
162     return NapiAsyncWork::Enqueue(env, context, "GetAVPlaybackState", executor, complete);
163 }
164 
GetAVMetaData(napi_env env,napi_callback_info info)165 napi_value NapiAVSessionController::GetAVMetaData(napi_env env, napi_callback_info info)
166 {
167     struct ConcreteContext : public ContextBase {
168         AVMetaData data;
169     };
170     auto context = std::make_shared<ConcreteContext>();
171     context->GetCbInfo(env, info);
172 
173     auto executor = [context]() {
174         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
175         if (napiController->controller_ == nullptr) {
176             SLOGE("GetAVMetaData failed : controller is nullptr");
177             context->status = napi_generic_failure;
178             context->errMessage = "GetAVMetaData failed : controller is nullptr";
179             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
180             return;
181         }
182         int32_t ret = napiController->controller_->GetAVMetaData(context->data);
183         if (ret != AVSESSION_SUCCESS) {
184             if (ret == ERR_SESSION_NOT_EXIST) {
185                 context->errMessage = "GetAVMetaData failed : native session not exist";
186             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
187                 context->errMessage = "GetAVMetaData failed : native controller not exist";
188             } else {
189                 context->errMessage = "GetAVMetaData failed : native server exception";
190             }
191             SLOGE("controller GetAVMetaData failed:%{public}d", ret);
192             context->status = napi_generic_failure;
193             context->errCode = NapiAVSessionManager::errcode_[ret];
194         }
195     };
196 
197     auto complete = [env, context](napi_value& output) {
198         context->status = NapiMetaData::SetValue(env, context->data, output);
199         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
200             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
201     };
202 
203     return NapiAsyncWork::Enqueue(env, context, "GetAVMetaData", executor, complete);
204 }
205 
SendAVKeyEvent(napi_env env,napi_callback_info info)206 napi_value NapiAVSessionController::SendAVKeyEvent(napi_env env, napi_callback_info info)
207 {
208     AVSESSION_TRACE_SYNC_START("NapiAVSessionController::SendAVKeyEvent");
209     struct ConcreteContext : public ContextBase {
210         std::shared_ptr<MMI::KeyEvent> keyEvent_;
211     };
212     auto context = std::make_shared<ConcreteContext>();
213     auto input = [env, context](size_t argc, napi_value* argv) {
214         CHECK_ARGS_RETURN_VOID(context, argc == ARGC_ONE, "invalid arguments",
215             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
216         context->status = NapiUtils::GetValue(env, argv[ARGV_FIRST], context->keyEvent_);
217         CHECK_ARGS_RETURN_VOID(context, (context->status == napi_ok) && (context->keyEvent_ != nullptr),
218             "invalid keyEvent", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
219     };
220     context->GetCbInfo(env, info, input);
221     context->taskId = NAPI_SEND_AV_KEY_EVENT_TASK_ID;
222 
223     auto executor = [context]() {
224         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
225         if (napiController->controller_ == nullptr) {
226             SLOGE("SendAVKeyEvent failed : controller is nullptr");
227             context->status = napi_generic_failure;
228             context->errMessage = "SendAVKeyEvent failed : controller is nullptr";
229             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
230             return;
231         }
232         int32_t ret = napiController->controller_->SendAVKeyEvent(*context->keyEvent_);
233         if (ret != AVSESSION_SUCCESS) {
234             if (ret == ERR_SESSION_NOT_EXIST) {
235                 context->errMessage = "SendAVKeyEvent failed : native session not exist";
236             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
237                 context->errMessage = "SendAVKeyEvent failed : native controller not exist";
238             } else if (ret == ERR_SESSION_DEACTIVE) {
239                 context->errMessage = "SendAVKeyEvent failed : native session is not active";
240             } else if (ret == ERR_COMMAND_NOT_SUPPORT) {
241                 context->errMessage = "SendAVKeyEvent failed : native invalid KeyEvent";
242             } else {
243                 context->errMessage = "SendAVKeyEvent failed : native server exception";
244             }
245             SLOGE("controller SendAVKeyEvent failed:%{public}d", ret);
246             context->status = napi_generic_failure;
247             context->errCode = NapiAVSessionManager::errcode_[ret];
248         }
249     };
250 
251     return NapiAsyncWork::Enqueue(env, context, "SendAVKeyEvent", executor);
252 }
253 
GetLaunchAbility(napi_env env,napi_callback_info info)254 napi_value NapiAVSessionController::GetLaunchAbility(napi_env env, napi_callback_info info)
255 {
256     struct ConcreteContext : public ContextBase {
257         AbilityRuntime::WantAgent::WantAgent ability;
258     };
259     auto context = std::make_shared<ConcreteContext>();
260     context->GetCbInfo(env, info);
261 
262     auto executor = [context]() {
263         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
264         if (napiController->controller_ == nullptr) {
265             SLOGE("GetLaunchAbility failed : controller is nullptr");
266             context->status = napi_generic_failure;
267             context->errMessage = "GetLaunchAbility failed : controller is nullptr";
268             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
269             return;
270         }
271         int32_t ret = napiController->controller_->GetLaunchAbility(context->ability);
272         if (ret != AVSESSION_SUCCESS) {
273             if (ret == ERR_SESSION_NOT_EXIST) {
274                 context->errMessage = "GetLaunchAbility failed : native session not exist";
275             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
276                 context->errMessage = "GetLaunchAbility failed : native controller not exist";
277             } else {
278                 context->errMessage = "GetLaunchAbility failed : native server exception";
279             }
280             SLOGE("controller GetLaunchAbility failed:%{public}d", ret);
281             context->status = napi_generic_failure;
282             context->errCode = NapiAVSessionManager::errcode_[ret];
283         }
284     };
285 
286     auto complete = [env, context](napi_value& output) {
287         context->status = NapiUtils::SetValue(env, context->ability, output);
288         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
289             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
290     };
291 
292     return NapiAsyncWork::Enqueue(env, context, "GetLaunchAbility", executor, complete);
293 }
294 
GetValidCommands(napi_env env,napi_callback_info info)295 napi_value NapiAVSessionController::GetValidCommands(napi_env env, napi_callback_info info)
296 {
297     struct ConcreteContext : public ContextBase {
298         std::vector<std::string> stringCmds;
299     };
300     auto context = std::make_shared<ConcreteContext>();
301     context->GetCbInfo(env, info);
302 
303     auto executor = [context]() {
304         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
305         if (napiController->controller_ == nullptr) {
306             SLOGE("GetValidCommands failed : controller is nullptr");
307             context->status = napi_generic_failure;
308             context->errMessage = "GetValidCommands failed : controller is nullptr";
309             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
310             return;
311         }
312         std::vector<int32_t> cmds;
313         int32_t ret = napiController->controller_->GetValidCommands(cmds);
314         if (ret != AVSESSION_SUCCESS) {
315             if (ret == ERR_SESSION_NOT_EXIST) {
316                 context->errMessage = "GetValidCommands failed : native session not exist";
317             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
318                 context->errMessage = "GetValidCommands failed : native controller not exist";
319             } else {
320                 context->errMessage = "GetValidCommands failed : native server exception";
321             }
322             SLOGE("controller GetValidCommands failed:%{public}d", ret);
323             context->status = napi_generic_failure;
324             context->errCode = NapiAVSessionManager::errcode_[ret];
325         }
326         context->stringCmds = NapiControlCommand::ConvertCommands(cmds);
327     };
328 
329     auto complete = [env, context](napi_value& output) {
330         context->status = NapiUtils::SetValue(env, context->stringCmds, output);
331         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
332             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
333     };
334 
335     return NapiAsyncWork::Enqueue(env, context, "GetValidCommands", executor, complete);
336 }
337 
IsSessionActive(napi_env env,napi_callback_info info)338 napi_value NapiAVSessionController::IsSessionActive(napi_env env, napi_callback_info info)
339 {
340     struct ConcreteContext : public ContextBase {
341         bool isActive {};
342     };
343     auto context = std::make_shared<ConcreteContext>();
344     context->GetCbInfo(env, info);
345 
346     auto executor = [context]() {
347         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
348         if (napiController->controller_ == nullptr) {
349             SLOGE("IsSessionActive failed : controller is nullptr");
350             context->status = napi_generic_failure;
351             context->errMessage = "IsSessionActive failed : controller is nullptr";
352             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
353             return;
354         }
355         int32_t ret = napiController->controller_->IsSessionActive(context->isActive);
356         if (ret != AVSESSION_SUCCESS) {
357             if (ret == ERR_SESSION_NOT_EXIST) {
358                 context->errMessage = "IsSessionActive failed : native session not exist";
359             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
360                 context->errMessage = "IsSessionActive failed : native controller not exist";
361             } else {
362                 context->errMessage = "IsSessionActive failed : native server exception";
363             }
364             SLOGE("controller IsSessionActive failed:%{public}d", ret);
365             context->status = napi_generic_failure;
366             context->errCode = NapiAVSessionManager::errcode_[ret];
367         }
368     };
369 
370     auto complete = [env, context](napi_value& output) {
371         context->status = NapiUtils::SetValue(env, context->isActive, output);
372         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
373             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
374     };
375 
376     return NapiAsyncWork::Enqueue(env, context, "IsSessionActive", executor, complete);
377 }
378 
SendControlCommand(napi_env env,napi_callback_info info)379 napi_value NapiAVSessionController::SendControlCommand(napi_env env, napi_callback_info info)
380 {
381     AVSESSION_TRACE_SYNC_START("NapiAVSessionController::SendControlCommand");
382     struct ConcrentContext : public ContextBase {
383         AVControlCommand command;
384     };
385     auto context = std::make_shared<ConcrentContext>();
386     auto input = [env, context](size_t argc, napi_value* argv) {
387         CHECK_ARGS_RETURN_VOID(context, argc == ARGC_ONE, "invalid arguments",
388             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
389         context->status = NapiControlCommand::GetValue(env, argv[ARGV_FIRST], context->command);
390         CHECK_ARGS_RETURN_VOID(context, (context->status == napi_ok), "invalid command",
391             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
392     };
393     context->GetCbInfo(env, info, input);
394     context->taskId = NAPI_SEND_CONTROL_COMMAND_TASK_ID;
395 
396     auto executor = [context]() {
397         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
398         if (napiController->controller_ == nullptr) {
399             SLOGE("SendControlCommand failed : controller is nullptr");
400             context->status = napi_generic_failure;
401             context->errMessage = "SendControlCommand failed : controller is nullptr";
402             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
403             return;
404         }
405         int32_t ret = napiController->controller_->SendControlCommand(context->command);
406         if (ret != AVSESSION_SUCCESS) {
407             if (ret == ERR_SESSION_NOT_EXIST) {
408                 context->errMessage = "SendControlCommand failed : native session not exist";
409             } else if (ret == ERR_CONTROLLER_NOT_EXIST) {
410                 context->errMessage = "SendControlCommand failed : native controller not exist";
411             } else if (ret == ERR_SESSION_DEACTIVE) {
412                 context->errMessage = "SendControlCommand failed : native session is not active";
413             } else if (ret == ERR_COMMAND_NOT_SUPPORT) {
414                 context->errMessage = "SendControlCommand failed : native command not support";
415             } else if (ret == ERR_COMMAND_SEND_EXCEED_MAX) {
416                 context->errMessage = "SendControlCommand failed : native command send nums overload";
417             } else {
418                 context->errMessage = "SendControlCommand failed : native server exception";
419             }
420             SLOGE("controller SendControlCommand failed:%{public}d", ret);
421             context->status = napi_generic_failure;
422             context->errCode = NapiAVSessionManager::errcode_[ret];
423         }
424     };
425 
426     return NapiAsyncWork::Enqueue(env, context, "SendControlCommand", executor);
427 }
428 
Destroy(napi_env env,napi_callback_info info)429 napi_value NapiAVSessionController::Destroy(napi_env env, napi_callback_info info)
430 {
431     auto context = std::make_shared<ContextBase>();
432     if (context == nullptr) {
433         SLOGE("OnEvent failed : no memory");
434         NapiUtils::ThrowError(env, "OnEvent failed : no memory", NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
435         return NapiUtils::GetUndefinedValue(env);
436     }
437 
438     context->GetCbInfo(env, info);
439 
440     auto executor = [context]() {
441         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
442         if (napiController->controller_ == nullptr) {
443             SLOGE("Destroy controller failed : controller is nullptr");
444             context->status = napi_generic_failure;
445             context->errMessage = "Destroy controller failed : controller is nullptr";
446             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
447             return;
448         }
449         int32_t ret = napiController->controller_->Destroy();
450         if (ret != AVSESSION_SUCCESS) {
451             if (ret == ERR_CONTROLLER_NOT_EXIST) {
452                 context->errMessage = "Destroy controller failed : native controller not exist";
453             } else {
454                 context->errMessage = "Destroy controller failed : native server exception";
455             }
456             SLOGE("controller Destroy failed:%{public}d", ret);
457             context->status = napi_generic_failure;
458             context->errCode = NapiAVSessionManager::errcode_[ret];
459             return;
460         }
461         napiController->controller_ = nullptr;
462         napiController->callback_ = nullptr;
463     };
464 
465     return NapiAsyncWork::Enqueue(env, context, "IsSessionActive", executor);
466 }
467 
GetRealPlaybackPositionSync(napi_env env,napi_callback_info info)468 napi_value NapiAVSessionController::GetRealPlaybackPositionSync(napi_env env, napi_callback_info info)
469 {
470     auto context = std::make_shared<ContextBase>();
471     if (context == nullptr) {
472         SLOGE("OnEvent failed : no memory");
473         NapiUtils::ThrowError(env, "OnEvent failed : no memory", NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
474         return NapiUtils::GetUndefinedValue(env);
475     }
476 
477     context->GetCbInfo(env, info, NapiCbInfoParser(), true);
478 
479     auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
480     if (napiController->controller_ == nullptr) {
481         SLOGI("GetRealPlaybackPositionSync failed : controller is nullptr");
482         NapiUtils::ThrowError(env, "GetRealPlaybackPositionSync failed : controller is nullptr",
483             NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST]);
484         return NapiUtils::GetUndefinedValue(env);
485     }
486 
487     auto position = napiController->controller_->GetRealPlaybackPosition();
488     napi_value output {};
489     auto status = NapiUtils::SetValue(env, position, output);
490     if (status != napi_ok) {
491         SLOGE("convert native object to javascript object failed");
492         NapiUtils::ThrowError(env, "convert native object to javascript object failed",
493             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
494         return NapiUtils::GetUndefinedValue(env);
495     }
496     return output;
497 }
498 
GetOutputDevice(napi_env env,napi_callback_info info)499 napi_value NapiAVSessionController::GetOutputDevice(napi_env env, napi_callback_info info)
500 {
501     struct ConcreteContext : public ContextBase {
502         OutputDeviceInfo outputDeviceInfo_;
503     };
504     auto context = std::make_shared<ConcreteContext>();
505     context->GetCbInfo(env, info);
506 
507     auto executor = [context]() {
508         auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
509         if (napiController->controller_ == nullptr) {
510             SLOGE("GetOutputDevice failed : controller is nullptr");
511             context->status = napi_generic_failure;
512             context->errMessage = "GetOutputDevice failed : controller is nullptr";
513             context->errCode = NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST];
514             return;
515         }
516         AVSessionDescriptor descriptor;
517         AVSessionManager::GetInstance().GetSessionDescriptorsBySessionId(napiController->controller_->GetSessionId(),
518                                                                          descriptor);
519         context->outputDeviceInfo_ = descriptor.outputDeviceInfo_;
520     };
521 
522     auto complete = [env, context](napi_value& output) {
523         context->status = NapiUtils::SetValue(env, context->outputDeviceInfo_, output);
524         CHECK_STATUS_RETURN_VOID(context, "convert native object to javascript object failed",
525             NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
526     };
527     return NapiAsyncWork::Enqueue(env, context, "GetOutputDevice", executor, complete);
528 }
529 
SetPlaybackStateFilter(napi_env env,NapiAVSessionController * napiController,napi_value filter)530 napi_status NapiAVSessionController::SetPlaybackStateFilter(napi_env env, NapiAVSessionController *napiController,
531                                                             napi_value filter)
532 {
533     AVPlaybackState::PlaybackStateMaskType playbackMask;
534     auto status = NapiPlaybackState::ConvertFilter(env, filter, playbackMask);
535     CHECK_RETURN(status == napi_ok, "convert filter failed", status);
536     auto ret = napiController->controller_->SetPlaybackFilter(playbackMask);
537     if (ret != AVSESSION_SUCCESS) {
538         SLOGE("controller SetPlaybackFilter failed:%{public}d", ret);
539         status = napi_generic_failure;
540     }
541     return status;
542 }
543 
SetMetaFilter(napi_env env,NapiAVSessionController * napiController,napi_value filter)544 napi_status NapiAVSessionController::SetMetaFilter(napi_env env, NapiAVSessionController* napiController,
545                                                    napi_value filter)
546 {
547     AVMetaData::MetaMaskType metaMask;
548     auto status = NapiMetaData::ConvertFilter(env, filter, metaMask);
549     CHECK_RETURN(status == napi_ok, "convert filter failed", status);
550     auto ret = napiController->controller_->SetMetaFilter(metaMask);
551     if (ret != AVSESSION_SUCCESS) {
552         SLOGE("controller SetMetaFilter failed:%{public}d", ret);
553         status = napi_generic_failure;
554     }
555     return status;
556 }
557 
RegisterCallback(napi_env env,const std::shared_ptr<ContextBase> & context,const std::string & event,napi_value filter,napi_value callback)558 napi_status NapiAVSessionController::RegisterCallback(napi_env env, const std::shared_ptr<ContextBase>& context,
559     const std::string& event, napi_value filter, napi_value callback)
560 {
561     auto it = EventHandlers_.find(event);
562     if (it == EventHandlers_.end()) {
563         SLOGE("event name invalid");
564         NapiUtils::ThrowError(env, "event name invalid", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
565         return napi_generic_failure;
566     }
567     auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
568     if (napiController->controller_ == nullptr) {
569         SLOGE("OnEvent failed : controller is nullptr");
570         NapiUtils::ThrowError(env, "OnEvent failed : controller is nullptr",
571             NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST]);
572         return napi_generic_failure;
573     }
574     if (napiController->callback_ == nullptr) {
575         napiController->callback_= std::make_shared<NapiAVControllerCallback>();
576         if (napiController->callback_ == nullptr) {
577             SLOGE("OnEvent failed : no memory");
578             NapiUtils::ThrowError(env, "OnEvent failed : no memory",
579                 NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
580             return napi_generic_failure;
581         }
582         auto ret = napiController->controller_->RegisterCallback(napiController->callback_);
583         if (ret != AVSESSION_SUCCESS) {
584             SLOGE("controller RegisterCallback failed:%{public}d", ret);
585             if (ret == ERR_CONTROLLER_NOT_EXIST) {
586                 NapiUtils::ThrowError(env, "OnEvent failed : native controller not exist",
587                     NapiAVSessionManager::errcode_[ERR_CONTROLLER_NOT_EXIST]);
588                 return napi_generic_failure;
589             } else if (ret == ERR_NO_MEMORY) {
590                 NapiUtils::ThrowError(env, "OnEvent failed : native no memory",
591                     NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
592                 return napi_generic_failure;
593             } else {
594                 NapiUtils::ThrowError(env, "OnEvent failed : native server exception",
595                     NapiAVSessionManager::errcode_[ret]);
596                 return napi_generic_failure;
597             }
598         }
599     }
600     if (it->second.first(env, napiController, filter, callback) != napi_ok) {
601         SLOGE("add event callback failed");
602         NapiUtils::ThrowError(env, "add event callback failed", NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
603         return napi_generic_failure;
604     }
605     return napi_ok;
606 }
607 
IsThreeParamForOnEvent(const std::string & event)608 static bool IsThreeParamForOnEvent(const std::string& event)
609 {
610     return event == "metadataChange" || event == "playbackStateChange";
611 }
612 
OnEvent(napi_env env,napi_callback_info info)613 napi_value NapiAVSessionController::OnEvent(napi_env env, napi_callback_info info)
614 {
615     auto context = std::make_shared<ContextBase>();
616     if (context == nullptr) {
617         SLOGE("OnEvent failed : no memory");
618         NapiUtils::ThrowError(env, "OnEvent failed : no memory", NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
619         return NapiUtils::GetUndefinedValue(env);
620     }
621 
622     std::string eventName;
623     napi_value filter {};
624     napi_value callback {};
625     auto input = [&eventName, &callback, &filter, env, &context](size_t argc, napi_value* argv) {
626         CHECK_ARGS_RETURN_VOID(context, argc >= ARGC_ONE, "invalid argument number",
627             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
628         context->status = NapiUtils::GetValue(env, argv[ARGV_FIRST], eventName);
629         CHECK_STATUS_RETURN_VOID(context, "get event name failed",
630             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
631         napi_valuetype type = napi_undefined;
632         if (!IsThreeParamForOnEvent(eventName)) {
633             CHECK_ARGS_RETURN_VOID(context, argc == ARGC_TWO, "invalid argument number",
634                 NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
635             context->status = napi_typeof(env, argv[ARGV_SECOND], &type);
636             CHECK_ARGS_RETURN_VOID(context, (context->status == napi_ok) && (type == napi_function),
637                                    "callback type invalid", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
638             callback = argv[ARGV_SECOND];
639         } else {
640             CHECK_ARGS_RETURN_VOID(context, argc == ARGC_THERE, "invalid argument number",
641                 NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
642             context->status = napi_typeof(env, argv[ARGV_SECOND], &type);
643             CHECK_ARGS_RETURN_VOID(
644                 context, (context->status == napi_ok) && (type == napi_object || type == napi_string),
645                 "filter type invalid", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
646             filter = argv[ARGV_SECOND];
647             context->status = napi_typeof(env, argv[ARGV_THIRD], &type);
648             CHECK_ARGS_RETURN_VOID(context, (context->status == napi_ok) && (type == napi_function),
649                                    "callback type invalid", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
650             callback = argv[ARGV_THIRD];
651         }
652     };
653     context->GetCbInfo(env, info, input, true);
654     if (context->status != napi_ok) {
655         NapiUtils::ThrowError(env, context->errMessage.c_str(), context->errCode);
656         return NapiUtils::GetUndefinedValue(env);
657     }
658 
659     RegisterCallback(env, context, eventName, filter, callback);
660 
661     return NapiUtils::GetUndefinedValue(env);
662 }
663 
OffEvent(napi_env env,napi_callback_info info)664 napi_value NapiAVSessionController::OffEvent(napi_env env, napi_callback_info info)
665 {
666     auto context = std::make_shared<ContextBase>();
667     if (context == nullptr) {
668         SLOGE("OnEvent failed : no memory");
669         NapiUtils::ThrowError(env, "OnEvent failed : no memory", NapiAVSessionManager::errcode_[ERR_NO_MEMORY]);
670         return NapiUtils::GetUndefinedValue(env);
671     }
672 
673     std::string eventName;
674     napi_value callback = nullptr;
675     auto input = [&eventName, env, &context, &callback](size_t argc, napi_value* argv) {
676         CHECK_ARGS_RETURN_VOID(context, argc == ARGC_ONE || argc == ARGC_TWO, "invalid argument number",
677             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
678         context->status = NapiUtils::GetValue(env, argv[ARGV_FIRST], eventName);
679         CHECK_STATUS_RETURN_VOID(context, "get event name failed",
680             NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
681         if (argc == ARGC_TWO) {
682             callback = argv[ARGV_SECOND];
683         }
684     };
685 
686     context->GetCbInfo(env, info, input, true);
687     if (context->status != napi_ok) {
688         NapiUtils::ThrowError(env, context->errMessage.c_str(), context->errCode);
689         return NapiUtils::GetUndefinedValue(env);
690     }
691 
692     auto it = EventHandlers_.find(eventName);
693     if (it == EventHandlers_.end()) {
694         SLOGE("event name invalid:%{public}s", eventName.c_str());
695         NapiUtils::ThrowError(env, "event name invalid", NapiAVSessionManager::errcode_[ERR_INVALID_PARAM]);
696         return NapiUtils::GetUndefinedValue(env);
697     }
698 
699     auto* napiController = reinterpret_cast<NapiAVSessionController*>(context->native);
700     if (napiController->callback_ == nullptr) {
701         SLOGI("function %{public}s not register yet", eventName.c_str());
702         return NapiUtils::GetUndefinedValue(env);
703     }
704 
705     if (it->second.second(env, napiController, callback) != napi_ok) {
706         NapiUtils::ThrowError(env, "remove event callback failed", NapiAVSessionManager::errcode_[AVSESSION_ERROR]);
707     }
708     return NapiUtils::GetUndefinedValue(env);
709 }
710 
OnSessionDestroy(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)711 napi_status NapiAVSessionController::OnSessionDestroy(napi_env env, NapiAVSessionController* napiController,
712                                                       napi_value param, napi_value callback)
713 {
714     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_SESSION_DESTROY, callback);
715 }
716 
OnPlaybackStateChange(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)717 napi_status NapiAVSessionController::OnPlaybackStateChange(napi_env env, NapiAVSessionController* napiController,
718                                                            napi_value param, napi_value callback)
719 {
720     if (SetPlaybackStateFilter(env, napiController, param) != napi_ok) {
721         return napi_generic_failure;
722     }
723     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_PLAYBACK_STATE_CHANGE,
724                                                   callback);
725 }
726 
OnMetaDataChange(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)727 napi_status NapiAVSessionController::OnMetaDataChange(napi_env env, NapiAVSessionController* napiController,
728                                                       napi_value param, napi_value callback)
729 {
730     if (SetMetaFilter(env, napiController, param) != napi_ok) {
731         return napi_generic_failure;
732     }
733     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_META_DATA_CHANGE, callback);
734 }
735 
OnActiveStateChange(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)736 napi_status NapiAVSessionController::OnActiveStateChange(napi_env env, NapiAVSessionController* napiController,
737                                                          napi_value param, napi_value callback)
738 {
739     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_ACTIVE_STATE_CHANGE, callback);
740 }
741 
OnValidCommandChange(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)742 napi_status NapiAVSessionController::OnValidCommandChange(napi_env env, NapiAVSessionController* napiController,
743                                                           napi_value param, napi_value callback)
744 {
745     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_VALID_COMMAND_CHANGE,
746                                                   callback);
747 }
748 
OnOutputDeviceChange(napi_env env,NapiAVSessionController * napiController,napi_value param,napi_value callback)749 napi_status NapiAVSessionController::OnOutputDeviceChange(napi_env env, NapiAVSessionController* napiController,
750                                                           napi_value param, napi_value callback)
751 {
752     return napiController->callback_->AddCallback(env, NapiAVControllerCallback::EVENT_OUTPUT_DEVICE_CHANGE,
753                                                   callback);
754 }
755 
OffSessionDestroy(napi_env env,NapiAVSessionController * napiController,napi_value callback)756 napi_status NapiAVSessionController::OffSessionDestroy(napi_env env, NapiAVSessionController* napiController,
757                                                        napi_value callback)
758 {
759     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_SESSION_DESTROY, callback);
760 }
761 
OffPlaybackStateChange(napi_env env,NapiAVSessionController * napiController,napi_value callback)762 napi_status NapiAVSessionController::OffPlaybackStateChange(napi_env env, NapiAVSessionController* napiController,
763                                                             napi_value callback)
764 {
765     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_PLAYBACK_STATE_CHANGE,
766                                                      callback);
767 }
768 
OffMetaDataChange(napi_env env,NapiAVSessionController * napiController,napi_value callback)769 napi_status NapiAVSessionController::OffMetaDataChange(napi_env env, NapiAVSessionController* napiController,
770                                                        napi_value callback)
771 {
772     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_META_DATA_CHANGE, callback);
773 }
774 
OffActiveStateChange(napi_env env,NapiAVSessionController * napiController,napi_value callback)775 napi_status NapiAVSessionController::OffActiveStateChange(napi_env env, NapiAVSessionController* napiController,
776                                                           napi_value callback)
777 {
778     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_ACTIVE_STATE_CHANGE,
779                                                      callback);
780 }
781 
OffValidCommandChange(napi_env env,NapiAVSessionController * napiController,napi_value callback)782 napi_status NapiAVSessionController::OffValidCommandChange(napi_env env, NapiAVSessionController* napiController,
783                                                            napi_value callback)
784 {
785     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_VALID_COMMAND_CHANGE,
786                                                      callback);
787 }
788 
OffOutputDeviceChange(napi_env env,NapiAVSessionController * napiController,napi_value callback)789 napi_status NapiAVSessionController::OffOutputDeviceChange(napi_env env, NapiAVSessionController* napiController,
790                                                            napi_value callback)
791 {
792     return napiController->callback_->RemoveCallback(env, NapiAVControllerCallback::EVENT_OUTPUT_DEVICE_CHANGE,
793                                                      callback);
794 }
795 }