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 }