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