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