diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000..2b2dfc6 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +config("cast_engine_default_config") { + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-Wno-shadow", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", + "-FS", + "-O2", + "-D_FORTIFY_SOURCE=2", + "-fvisibility=hidden", + "-fvisibility-inlines-hidden" + ] + cflags_cc = cflags + ldflags = [ "-Werror" ] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c938870 --- /dev/null +++ b/LICENSE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.en.md b/README.en.md deleted file mode 100644 index ef16e86..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# castengine_cast_framework - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 99c0d3d..865ccec 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,41 @@ # castengine_cast_framework -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +## Introduction -#### 软件架构 -软件架构说明 +Provide audio and video broadcasting capabilities with adaptive Cast+Stream, Wi Fi Display, and DLNA protocols, providing a unified interface and normalized experience for north-south developers. +## Directory Structure -#### 安装教程 +``` +/foundation/CastEngine/castengine_cast_framework +├── clinet # Implementation on the client side +├── common # common code +├── etc # SA profile file +├── interfaces # Inner api +├── sa_profile # SA profile +├── service # Implementation on the service side +├── LICENSE # Certificate file +├── BUILD.gn # Compilation Entry +├── test # test code +└── bundle.json # Component description file -1. xxxx -2. xxxx -3. xxxx +``` -#### 使用说明 +## Compilation and Building -1. xxxx -2. xxxx -3. xxxx +``` +# Generate the libcast.z.so、libcast_engine_client.z.so、libcast_engine_service.z.so file in the out directory of the product folder through GN compilation. +hb build cast +``` -#### 参与贡献 +### Usage -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +For details, see[Sample](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Media/AVSession)。 +## Repositories Involved -#### 特技 +[castengine_cast_plus_stream](https://gitee.com/openharmony-sig/castengine_cast_plus_stream) -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +[castengine_wifi_display](https://gitee.com/openharmony-sig/castengine_wifi_display) + +[castengine_dlna](https://gitee.com/openharmony-sig/castengine_dlna) \ No newline at end of file diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000..82b189e --- /dev/null +++ b/README_zh.md @@ -0,0 +1,41 @@ +# 音视频投播管理服务框架部件 + +## 简介 + +提供自适应Cast+ Stream,Wi-Fi Display,DLNA多种协议的音视频投播能力,为南北向开发者提供统一的接口及归一化的体验。 + +## 目录 + +``` +/foundation/CastEngine/castengine_cast_framework # 音视频投播管理服务框架业务代码 +├── clinet # 客户端实现 +├── common # 公共引用 +├── etc # SA描述 +├── interfaces # 接口文件 +├── sa_profile # SA profile文件 +├── service # 服务端实现 +├── LICENSE # 证书文件 +├── BUILD.gn # 编译入口 +├── test # 测试代码 +└── bundle.json # 部件描述文件 +``` + +## 编译构建 + +``` +# 通过gn编译,在out目录下对应产品的文件夹中生成libcast.z.so、libcast_engine_client.z.so、libcast_engine_service.z.so +hb build cast +``` + +### 使用说明 + +提供整体的投播框架,支持其他投屏协议的接入以及投屏协议自适应选择。 +北向接入可参考[Sample](https://gitee.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Media/AVSession)。 + +## 相关仓 + +[castengine_cast_plus_stream](https://gitee.com/openharmony-sig/castengine_cast_plus_stream) + +[castengine_wifi_display](https://gitee.com/openharmony-sig/castengine_wifi_display) + +[castengine_dlna](https://gitee.com/openharmony-sig/castengine_dlna) \ No newline at end of file diff --git a/bundle.json b/bundle.json new file mode 100644 index 0000000..32d6ce1 --- /dev/null +++ b/bundle.json @@ -0,0 +1,88 @@ +{ + "name":"@ohos/cast_engine", + "description":"supply cast engine service", + "version":"3.1", + "license":"", + "publishAs":"binary", + "dirs":{}, + "scripts":{}, + "component":{ + "name":"cast_engine", + "subsystem":"castplus", + "syscap":[ + "" + ], + "features":[], + "adapted_system_type":[ + "standard" + ], + "rom":"5M", + "ram":"50M", + "hisysevent_config": [ + "//foundation/CastEngine/castengine_cast_framework/hisysevent.yaml" + ], + "deps":{ + "components":[ + "hilog", + "hisysevent", + "hitrace", + "access_token", + "audio_framework", + "av_codec", + "ipc", + "init", + "input", + "safwk", + "samgr", + "c_utils", + "dsoftbus", + "device_manager", + "common_event_service", + "bundle_framework", + "ability_base", + "ability_runtime", + "ace_engine", + "napi", + "graphic_2d", + "window_manager", + "player_framework" + ], + "third_party":[ + "glib", + "json", + "jsoncpp", + "openssl", + "bounds_checking_function" + ] + }, + "build":{ + "sub_component":[ + "//foundation/CastEngine/castengine_cast_framework/service:cast_engine_service", + "//foundation/CastEngine/castengine_cast_framework/interfaces/inner_api:cast_engine_client", + "//foundation/CastEngine/castengine_cast_framework/sa_profile:cast_engine_sa_profile", + "//foundation/CastEngine/castengine_cast_framework/etc/init:cast_engine_service.cfg", + "//foundation/CastEngine/castengine_cast_framework/interfaces/kits/js:cast" + ], + "inner_kits":[ + { + "type": "so", + "name": "//foundation/CastEngine/castengine_cast_framework/interfaces/inner_api:cast_engine_client", + "header": { + "header_base": "//foundation/CastEngine/castengine_cast_framework/interfaces/inner_api/include", + "header_files": [ + "cast_engine_common.h", + "cast_session_manager.h", + "i_cast_session.h", + "i_cast_session_manager_adaptor.h", + "i_cast_session_manager_listener.h" + ] + } + } + ], + "test":[ + "//foundation/CastEngine/castengine_cast_framework/test:cast_unittest", + "//foundation/CastEngine/castengine_cast_framework/test/fuzztest:fuzztest" + ] + } + } +} diff --git a/cast_engine.gni b/cast_engine.gni new file mode 100644 index 0000000..fd9a4ea --- /dev/null +++ b/cast_engine.gni @@ -0,0 +1,21 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//build/ohos.gni") +import("//build/ohos_var.gni") + +cast_engine_root = get_path_info(".", "abspath") +cast_engine_client = "$cast_engine_root/client" +cast_engine_common = "$cast_engine_root/common" +cast_engine_interfaces = "$cast_engine_root/interfaces" +cast_engine_service = "$cast_engine_root/service" +cast_session_stream_path = "//foundation/CastEngine/castengine_cast_plus_stream" + +graphic_2d_path = "//foundation/graphic/graphic_2d" + +build_flags = [ "-Werror" ] diff --git a/client/BUILD.gn b/client/BUILD.gn new file mode 100644 index 0000000..e2ec435 --- /dev/null +++ b/client/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_client_config") { + include_dirs = [ + "include", + "${cast_engine_interfaces}/inner_api/include", + ] +} + +ohos_static_library("cast_client_inner") { + sources = [ + "src/cast_service_listener_impl_stub.cpp", + "src/cast_session.cpp", + "src/cast_session_impl_proxy.cpp", + "src/cast_session_listener_impl_stub.cpp", + "src/cast_session_manager.cpp", + "src/cast_session_manager_adaptor.cpp", + "src/cast_session_manager_service_proxy.cpp", + "src/cast_engine_service_load_callback.cpp", + "src/stream_player_listener_impl_stub.cpp", + "src/mirror_player.cpp", + "src/mirror_player_impl_proxy.cpp", + "src/stream_player.cpp", + "src/stream_player_impl_proxy.cpp", + ] + + configs = [ + ":cast_client_config", + "${cast_engine_root}:cast_engine_default_config", + ] + + public_configs = [ ":cast_client_config" ] + + deps = [ + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "samgr:samgr_proxy", + "graphic_2d:surface" + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/client/include/cast_engine_service_load_callback.h b/client/include/cast_engine_service_load_callback.h new file mode 100644 index 0000000..b15b29f --- /dev/null +++ b/client/include/cast_engine_service_load_callback.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service proxy class + * Author: zhuzhibin + * Create: 2022-10-25 + */ + +#ifndef CAST_ENGINE_SERVICE_LOAD_CALLBACK_H +#define CAST_ENGINE_SERVICE_LOAD_CALLBACK_H +#include "system_ability_load_callback_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastEngineServiceLoadCallback : public SystemAbilityLoadCallbackStub { +public: + void OnLoadSystemAbilitySuccess(int32_t systemAbilityId, const sptr &remoteObject) override; + void OnLoadSystemAbilityFail(int32_t systemAbilityId) override; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif // CAST_ENGINE_SERVICE_LOAD_CALLBACK_H \ No newline at end of file diff --git a/client/include/cast_service_listener_impl_stub.h b/client/include/cast_service_listener_impl_stub.h new file mode 100644 index 0000000..1621d2e --- /dev/null +++ b/client/include/cast_service_listener_impl_stub.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast service listener implement proxy + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef CAST_SERVICE_LISTENER_IMPL_STUB_H +#define CAST_SERVICE_LISTENER_IMPL_STUB_H + +#include "cast_engine_common.h" +#include "cast_stub_helper.h" +#include "i_cast_service_listener_impl.h" +#include "i_cast_session_manager_listener.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastServiceListenerImplStub : public IRemoteStub { +public: + CastServiceListenerImplStub(std::shared_ptr userListener); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DECLARE_STUB_TASK_MAP(CastServiceListenerImplStub); + + bool GetCastRemoteDevices(MessageParcel &data, std::vector &deviceList); + bool GetCastSession(MessageParcel &data, std::shared_ptr &castSession); + int32_t DoDeviceFoundTask(MessageParcel &data, MessageParcel &reply); + int32_t DoDeviceOfflineTask(MessageParcel &data, MessageParcel &reply); + int32_t DoSessionCreateTask(MessageParcel &data, MessageParcel &reply); + int32_t DoServiceDieTask(MessageParcel &data, MessageParcel &reply); + void OnDeviceFound(const std::vector &deviceList) override; + void OnDeviceOffline(const std::string &deviceId) override; + void OnSessionCreated(const sptr &castSession) override; + void OnServiceDied() override; + + std::shared_ptr userListener_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/client/include/cast_session.h b/client/include/cast_session.h new file mode 100644 index 0000000..4d007fb --- /dev/null +++ b/client/include/cast_session.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply Cast session definition. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_SESSION_H +#define CAST_SESSION_H + +#include "cast_engine_common.h" +#include "i_cast_session.h" +#include "i_cast_session_impl.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastSession : public ICastSession { +public: + CastSession(sptr proxy) : proxy_(proxy) {}; + ~CastSession() override; + + int32_t RegisterListener(std::shared_ptr listener) override; + int32_t UnregisterListener() override; + int32_t AddDevice(const CastRemoteDevice &remoteDevice) override; + int32_t RemoveDevice(const std::string &deviceId) override; + int32_t StartAuth(const AuthInfo &authInfo) override; + int32_t GetSessionId(std::string &sessionId) override; + int32_t SetSessionProperty(const CastSessionProperty &property) override; + int32_t SetSessionId(std::string sessionId); + int32_t CreateMirrorPlayer(std::shared_ptr &mirrorPlayer) override; + int32_t CreateStreamPlayer(std::shared_ptr &streamPlayer) override; + int32_t Release() override; + int32_t NotifyEvent(EventId eventId, std::string &jsonParam) override; + int32_t SetCastMode(CastMode mode, std::string &jsonParam) override; + +private: + sptr proxy_; + std::string sessionId_{}; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/client/include/cast_session_impl_proxy.h b/client/include/cast_session_impl_proxy.h new file mode 100644 index 0000000..c0699fb --- /dev/null +++ b/client/include/cast_session_impl_proxy.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session implement proxy + * Author: zhangge + * Create: 2022-5-29 + */ + +#ifndef CAST_SESSION_IMPL_PROXY_H +#define CAST_SESSION_IMPL_PROXY_H + +#include "cast_engine_common.h" +#include "i_cast_session_impl.h" +#include "iremote_proxy.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastSessionImplProxy : public IRemoteProxy { +public: + explicit CastSessionImplProxy(const sptr &impl) : IRemoteProxy(impl) {} + ~CastSessionImplProxy() override; + + int32_t RegisterListener(sptr listener) override; + int32_t UnregisterListener() override; + int32_t AddDevice(const CastRemoteDevice &remoteDevice) override; + int32_t RemoveDevice(const std::string &deviceId) override; + int32_t StartAuth(const AuthInfo &authInfo) override; + int32_t GetSessionId(std::string &sessionId) override; + int32_t GetDeviceState(const std::string &deviceId, DeviceState &deviceState) override; + int32_t SetSessionProperty(const CastSessionProperty &property) override; + int32_t CreateMirrorPlayer(sptr &mirrorPlayer) override; + int32_t CreateStreamPlayer(sptr &streamPlayer) override; + int32_t Release() override; + int32_t NotifyEvent(EventId eventId, std::string &jsonParam) override; + int32_t SetCastMode(CastMode mode, std::string &jsonParam) override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_PROXY_H \ No newline at end of file diff --git a/client/include/cast_session_listener_impl_stub.h b/client/include/cast_session_listener_impl_stub.h new file mode 100644 index 0000000..3e3f328 --- /dev/null +++ b/client/include/cast_session_listener_impl_stub.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session listener implement proxy apis. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef CAST_SESSION_LISTENER_STUB_H +#define CAST_SESSION_LISTENER_STUB_H + +#include "cast_stub_helper.h" +#include "i_cast_session_listener_impl.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastSessionListenerImplStub : public IRemoteStub { +public: + CastSessionListenerImplStub(std::shared_ptr userListener); + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DECLARE_STUB_TASK_MAP(CastSessionListenerImplStub); + + int32_t DoOnDeviceStateTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnEventTask(MessageParcel &data, MessageParcel &reply); + void OnDeviceState(const DeviceStateInfo &stateInfo) override; + void OnEvent(const EventId &eventId, const std::string &jsonParam) override; + std::shared_ptr userListener_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/client/include/cast_session_manager_adaptor.h b/client/include/cast_session_manager_adaptor.h new file mode 100644 index 0000000..f94a3bc --- /dev/null +++ b/client/include/cast_session_manager_adaptor.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager adaptor. + * Author: zhangge + * Create: 2022-5-29 + */ + +#ifndef CAST_SESSION_MANAGER_ADAPTOR_H +#define CAST_SESSION_MANAGER_ADAPTOR_H + +#include +#include +#include + +#include "cast_engine_common.h" +#include "cast_session_listener_impl_stub.h" +#include "cast_session_manager_service_proxy.h" +#include "i_cast_session_manager_adaptor.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastSessionManagerAdaptor : public ICastSessionManagerAdaptor, + public std::enable_shared_from_this { +public: + CastSessionManagerAdaptor(sptr proxy) : proxy_(proxy) {} + ~CastSessionManagerAdaptor() override; + + int32_t RegisterListener(std::shared_ptr listener, + sptr deathRecipient) override; + int32_t UnregisterListener() override; + int32_t Release() override; + int32_t SetLocalDevice(const CastLocalDevice &localDevice) override; + int32_t CreateCastSession(const CastSessionProperty &property, std::shared_ptr &castSession) override; + int32_t SetSinkSessionCapacity(int sessionCapacity) override; + int32_t StartDiscovery(int protocols) override; + int32_t SetDiscoverable(bool enable) override; + int32_t StopDiscovery() override; + int32_t GetCastSession(std::string sessionId, std::shared_ptr &castSession) override; + +private: + void UnsubscribeDeathRecipient(); + + sptr proxy_; + std::mutex mutex_; + wptr remote_; + sptr deathRecipient_{ nullptr }; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_SESSION_MANAGER_ADAPTOR_H \ No newline at end of file diff --git a/client/include/cast_session_manager_service_proxy.h b/client/include/cast_session_manager_service_proxy.h new file mode 100644 index 0000000..5b096ff --- /dev/null +++ b/client/include/cast_session_manager_service_proxy.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service proxy class + * Author: zhangge + * Create: 2022-5-29 + */ + +#ifndef CAST_SESSION_MANAGER_SERVICE_PROXY_H +#define CAST_SESSION_MANAGER_SERVICE_PROXY_H + +#include "cast_engine_common.h" +#include "i_cast_session_manager_service.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class CastSessionManagerServiceProxy : public IRemoteProxy { +public: + explicit CastSessionManagerServiceProxy(const sptr &impl) + : IRemoteProxy(impl) + {} + + int32_t RegisterListener(sptr listener) override; + int32_t UnregisterListener() override; + int32_t Release() override; + int32_t SetLocalDevice(const CastLocalDevice &localDevice) override; + int32_t CreateCastSession(const CastSessionProperty &property, sptr &castSession) override; + int32_t SetSinkSessionCapacity(int sessionCapacity) override; + int32_t StartDiscovery(int protocols) override; + int32_t SetDiscoverable(bool enable) override; + int32_t StopDiscovery() override; + sptr GetSessionManagerService(); + int32_t GetCastSession(std::string sessionId, sptr &castSession) override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + + +#endif // CAST_ENGINE_PROXY_H \ No newline at end of file diff --git a/client/include/mirror_player.h b/client/include/mirror_player.h new file mode 100644 index 0000000..9fa794a --- /dev/null +++ b/client/include/mirror_player.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply Cast mirror player definition. + * Author: zhangjingnan + * Create: 2023-05-27 + */ + +#ifndef MIRROR_PLAYER_H +#define MIRROR_PLAYER_H + +#include "cast_engine_common.h" +#include "i_mirror_player.h" +#include "i_mirror_player_impl.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class MirrorPlayer : public IMirrorPlayer { +public: + MirrorPlayer(sptr proxy) : proxy_(proxy) {}; + ~MirrorPlayer() override; + + int32_t Play(const std::string &deviceId) override; + int32_t Pause(const std::string &deviceId) override; + int32_t SetSurface(const std::string &surfaceId) override; + int32_t DeliverInputEvent(OHRemoteControlEvent event) override; + int32_t Release() override; + +private: + sptr proxy_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/client/include/mirror_player_impl_proxy.h b/client/include/mirror_player_impl_proxy.h new file mode 100644 index 0000000..9e19e1e --- /dev/null +++ b/client/include/mirror_player_impl_proxy.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply mirror player implement proxy + * Author: zhangjingnan + * Create: 2023-5-27 + */ + +#ifndef MIRROR_PLAYER_IMPL_PROXY_H +#define MIRROR_PLAYER_IMPL_PROXY_H + +#include "cast_engine_common.h" +#include "i_mirror_player_impl.h" +#include "iremote_proxy.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class MirrorPlayerImplProxy : public IRemoteProxy { +public: + explicit MirrorPlayerImplProxy(const sptr &impl) : IRemoteProxy(impl) {} + ~MirrorPlayerImplProxy() override; + + int32_t Play(const std::string &deviceId) override; + int32_t Pause(const std::string &deviceId) override; + int32_t SetSurface(sptr producer) override; + int32_t DeliverInputEvent(const OHRemoteControlEvent &event) override; + int32_t Release() override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_PROXY_H \ No newline at end of file diff --git a/client/include/stream_player.h b/client/include/stream_player.h new file mode 100644 index 0000000..6385dee --- /dev/null +++ b/client/include/stream_player.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply Stream Player definition. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#ifndef STREAM_PLAYER_H +#define STREAM_PLAYER_H + +#include "i_stream_player.h" +#include "i_stream_player_ipc.h" +#include "cast_engine_common.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class StreamPlayer : public IStreamPlayer { +public: + explicit StreamPlayer(sptr proxy) : proxy_(proxy) {} + ~StreamPlayer() override; + + int32_t RegisterListener(std::shared_ptr listener) override; + int32_t UnregisterListener() override; + int32_t SetSurface(const std::string &surfaceId) override; + int32_t Load(const MediaInfo &mediaInfo) override; + int32_t Play(const MediaInfo &mediaInfo) override; + int32_t Play(int index) override; + int32_t Play() override; + int32_t Pause() override; + int32_t Stop() override; + int32_t Next() override; + int32_t Previous() override; + int32_t Seek(int position) override; + int32_t FastForward(int delta) override; + int32_t FastRewind(int delta) override; + int32_t SetVolume(int volume) override; + int32_t SetLoopMode(const LoopMode mode) override; + int32_t SetSpeed(const PlaybackSpeed speed) override; + int32_t GetPlayerStatus(PlayerStates &playerStates) override; + int32_t GetPosition(int &position) override; + int32_t GetDuration(int &duration) override; + int32_t GetVolume(int &volume, int &maxVolume) override; + int32_t GetLoopMode(LoopMode &loopMode) override; + int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) override; + int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) override; + int32_t Release() override; + +private: + static const int GET_FAILED = -1; + sptr proxy_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/client/include/stream_player_impl_proxy.h b/client/include/stream_player_impl_proxy.h new file mode 100644 index 0000000..6b10313 --- /dev/null +++ b/client/include/stream_player_impl_proxy.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player implement proxy + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#ifndef STREAM_PLAYER_IMPL_PROXY_H +#define STREAM_PLAYER_IMPL_PROXY_H + +#include "i_stream_player_ipc.h" +#include "cast_engine_common.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class StreamPlayerImplProxy : public IRemoteProxy { +public: + explicit StreamPlayerImplProxy(const sptr &impl) : IRemoteProxy(impl) {} + ~StreamPlayerImplProxy() override; + + int32_t RegisterListener(sptr listener) override; + int32_t UnregisterListener() override; + int32_t SetSurface(sptr producer) override; + int32_t Load(const MediaInfo &mediaInfo) override; + int32_t Play(const MediaInfo &mediaInfo) override; + int32_t Play(int index) override; + int32_t Play() override; + int32_t Pause() override; + int32_t Stop() override; + int32_t Next() override; + int32_t Previous() override; + int32_t Seek(int position) override; + int32_t FastForward(int delta) override; + int32_t FastRewind(int delta) override; + int32_t SetVolume(int volume) override; + int32_t SetLoopMode(const LoopMode mode) override; + int32_t SetSpeed(const PlaybackSpeed speed) override; + int32_t GetPlayerStatus(PlayerStates &playerStates) override; + int32_t GetPosition(int &position) override; + int32_t GetDuration(int &duration) override; + int32_t GetVolume(int &volume, int &maxVolume) override; + int32_t GetLoopMode(LoopMode &loopMode) override; + int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) override; + int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) override; + int32_t Release() override; + +private: + static const int GET_FAILED = -1; + static inline BrokerDelegator delegator_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_PROXY_H \ No newline at end of file diff --git a/client/include/stream_player_listener_impl_stub.h b/client/include/stream_player_listener_impl_stub.h new file mode 100644 index 0000000..faef0c5 --- /dev/null +++ b/client/include/stream_player_listener_impl_stub.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player listener implement proxy apis. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#ifndef STREAM_PLAYER_LISTENER_IMPL_STUB_H +#define STREAM_PLAYER_LISTENER_IMPL_STUB_H + +#include "i_stream_player_listener_impl.h" +#include "i_stream_player.h" +#include "cast_stub_helper.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class StreamPlayerListenerImplStub : public IRemoteStub { +public: + explicit StreamPlayerListenerImplStub(std::shared_ptr userListener); + ~StreamPlayerListenerImplStub() override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DECLARE_STUB_TASK_MAP(StreamPlayerListenerImplStub); + + int32_t DoOnStateChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnPositionChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnMediaItemChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnVolumeChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnLoopModeChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnPlaySpeedChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnPlayerErrorTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnVideoSizeChangedTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnNextRequestTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnPreviousRequestTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnSeekDoneTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnEndOfStreamTask(MessageParcel &data, MessageParcel &reply); + int32_t DoOnPlayRequestTask(MessageParcel &data, MessageParcel &reply); + void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) override; + void OnPositionChanged(int position, int bufferPosition, int duration) override; + void OnMediaItemChanged(const MediaInfo &mediaInfo) override; + void OnVolumeChanged(int volume, int maxVolume) override; + void OnPlayerError(int errorCode, const std::string &errorMsg) override; + void OnVideoSizeChanged(int width, int height) override; + void OnLoopModeChanged(const LoopMode loopMode) override; + void OnPlaySpeedChanged(const PlaybackSpeed speed) override; + void OnNextRequest() override; + void OnPreviousRequest() override; + void OnSeekDone(int position) override; + void OnEndOfStream(int isLooping) override; + void OnPlayRequest(const MediaInfo &mediaInfo) override; + + std::shared_ptr userListener_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/client/src/cast_engine_service_load_callback.cpp b/client/src/cast_engine_service_load_callback.cpp new file mode 100644 index 0000000..5a3beb1 --- /dev/null +++ b/client/src/cast_engine_service_load_callback.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service proxy class + * Author: zhuzhibin + * Create: 2022-10-25 + */ + +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "system_ability_definition.h" +#include "cast_engine_service_load_callback.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-LoadServiceCallback"); + +void CastEngineServiceLoadCallback::OnLoadSystemAbilitySuccess(int32_t systemAbilityId, + const sptr &remoteObject) +{ + CLOGI("In systemAbilityId: %d", systemAbilityId); + if (systemAbilityId != CAST_ENGINE_SA_ID) { + CLOGE("Start aystemabilityId is not sinkSAId!"); + return; + } + if (remoteObject == nullptr) { + CLOGE("RemoteObject is nullptr."); + return; + } +} + +void CastEngineServiceLoadCallback::OnLoadSystemAbilityFail(int32_t systemAbilityId) +{ + CLOGI("In systemAbilityId: %d.", systemAbilityId); + if (systemAbilityId != CAST_ENGINE_SA_ID) { + CLOGE("Start aystemabilityId is not sinkSAId!"); + return; + } +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/client/src/cast_service_listener_impl_stub.cpp b/client/src/cast_service_listener_impl_stub.cpp new file mode 100644 index 0000000..c13ef84 --- /dev/null +++ b/client/src/cast_service_listener_impl_stub.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast service listener implement proxy apis. + * Author: zhangge + * Create: 2022-6-15 + */ + +#include "cast_service_listener_impl_stub.h" + +#include + +#include "cast_engine_common.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_log.h" +#include "cast_session.h" +#include "cast_stub_helper.h" +#include "i_cast_session_manager_listener.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-ServiceListener"); + +int CastServiceListenerImplStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + RETRUEN_IF_WRONG_TASK(code, data, reply, option); + return EXECUTE_SINGLE_STUB_TASK(code, data, reply); +} + +CastServiceListenerImplStub::CastServiceListenerImplStub(std::shared_ptr userListener) + : userListener_(userListener) +{ + FILL_SINGLE_STUB_TASK(ON_DEVICE_FOUND, &CastServiceListenerImplStub::DoDeviceFoundTask); + FILL_SINGLE_STUB_TASK(ON_DEVICE_OFFLINE, &CastServiceListenerImplStub::DoDeviceOfflineTask); + FILL_SINGLE_STUB_TASK(ON_SESSION_CREATE, &CastServiceListenerImplStub::DoSessionCreateTask); + FILL_SINGLE_STUB_TASK(ON_SERVICE_DIE, &CastServiceListenerImplStub::DoServiceDieTask); +} + +int32_t CastServiceListenerImplStub::DoServiceDieTask(MessageParcel &data, MessageParcel &reply) +{ + userListener_->OnServiceDied(); + return ERR_NONE; +} + +bool CastServiceListenerImplStub::GetCastRemoteDevices(MessageParcel &data, std::vector &deviceList) +{ + auto size = data.ReadInt32(); + if (size <= 0 || size > MAX_DEVICE_NUM) { + return false; + } + deviceList.resize(size); + for (int32_t i = 0; i < size; ++i) { + if (!ReadCastRemoteDevice(data, deviceList[i])) { + return false; + } + } + + return true; +} + +bool CastServiceListenerImplStub::GetCastSession(MessageParcel &data, std::shared_ptr &castSession) +{ + auto object = data.ReadRemoteObject(); + auto impl = (object == nullptr) ? nullptr : iface_cast(object); + if (impl == nullptr) { + CLOGE("Failed to cast ICastSessionImpl"); + return false; + } + + auto session = std::make_shared(impl); + if (session == nullptr) { + CLOGE("Failed to malloc cast session"); + return false; + } + castSession = session; + return true; +} + +int32_t CastServiceListenerImplStub::DoDeviceFoundTask(MessageParcel &data, MessageParcel &reply) +{ + CLOGI("DoOnDeviceStatusTask in"); + std::vector remoteDevices; + if (!GetCastRemoteDevices(data, remoteDevices)) { + CLOGE("DoDeviceFoundTask, failed get remote devices info"); + return ERR_INVALID_DATA; + } + userListener_->OnDeviceFound(remoteDevices); + + return ERR_NONE; +} + +int32_t CastServiceListenerImplStub::DoSessionCreateTask(MessageParcel &data, MessageParcel &reply) +{ + CLOGI("DoSessionCreateTask in"); + std::shared_ptr castSession; + if (!GetCastSession(data, castSession)) { + CLOGE("DoSessionCreateTask, failed get cast session info"); + return ERR_INVALID_DATA; + } + userListener_->OnSessionCreated(castSession); + + return ERR_NONE; +} + +int32_t CastServiceListenerImplStub::DoDeviceOfflineTask(MessageParcel &data, MessageParcel &reply) +{ + CLOGI("DoDeviceOfflineTask in"); + std::string deviceId = data.ReadString(); + if (deviceId.empty()) { + CLOGE("DoDeviceOfflineTask, failed get deviceId"); + return ERR_INVALID_DATA; + } + userListener_->OnDeviceOffline(deviceId); + return ERR_NONE; +} + +void CastServiceListenerImplStub::OnDeviceFound(const std::vector &deviceList) +{ + static_cast(deviceList); +} + +void CastServiceListenerImplStub::OnSessionCreated(const sptr &castSession) +{ + static_cast(castSession); +} + +void CastServiceListenerImplStub::OnServiceDied() {} + +void CastServiceListenerImplStub::OnDeviceOffline(const std::string &deviceId) +{ + static_cast(deviceId); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/cast_session.cpp b/client/src/cast_session.cpp new file mode 100644 index 0000000..38e649c --- /dev/null +++ b/client/src/cast_session.cpp @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast Session function realization. + * Author: zhangge + * Create: 2022-06-15 + */ + +#include "cast_session.h" + +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_session_listener_impl_stub.h" +#include "surface_utils.h" +#include "stream_player.h" +#include "mirror_player.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-Session"); + +CastSession::~CastSession() +{ + CLOGI("Stop the client cast session."); +} + +int32_t CastSession::RegisterListener(std::shared_ptr listener) +{ + if (listener == nullptr) { + CLOGE("The listener is null"); + return ERR_INVALID_PARAM; + } + sptr listenerStub = new (std::nothrow) CastSessionListenerImplStub(listener); + if (listenerStub == nullptr) { + CLOGE("Failed to new a session listener"); + return ERR_NO_MEMORY; + } + + return proxy_ ? proxy_->RegisterListener(listenerStub) : CAST_ENGINE_ERROR; +} + +int32_t CastSession::SetSessionId(std::string sessionId) +{ + sessionId_ = sessionId; + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSession::UnregisterListener() +{ + return proxy_ ? proxy_->UnregisterListener() : CAST_ENGINE_ERROR; +} + +int32_t CastSession::AddDevice(const CastRemoteDevice &remoteDevice) +{ + if (remoteDevice.deviceId.empty()) { + CLOGE("The remote device id is null"); + return ERR_INVALID_PARAM; + } + return proxy_ ? proxy_->AddDevice(remoteDevice) : CAST_ENGINE_ERROR; +} + +int32_t CastSession::RemoveDevice(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("The device id is null"); + return ERR_INVALID_PARAM; + } + return proxy_ ? proxy_->RemoveDevice(deviceId) : CAST_ENGINE_ERROR; +} + +int32_t CastSession::StartAuth(const AuthInfo &authInfo) +{ + if (authInfo.deviceId.empty()) { + CLOGE("The device id is null"); + return ERR_INVALID_PARAM; + } + return proxy_ ? proxy_->StartAuth(authInfo) : CAST_ENGINE_ERROR; +} + +int32_t CastSession::GetSessionId(std::string &sessionId) +{ + if (!proxy_) { + CLOGE("proxy is null"); + return CAST_ENGINE_ERROR; + } + int32_t ret = proxy_->GetSessionId(sessionId_); + sessionId = sessionId_; + return ret; +} + +int32_t CastSession::SetSessionProperty(const CastSessionProperty &property) +{ + return proxy_ ? proxy_->SetSessionProperty(property) : CAST_ENGINE_ERROR; +} + +int32_t CastSession::CreateMirrorPlayer(std::shared_ptr &mirrorPlayer) +{ + if (!proxy_) { + CLOGE("proxy_ is null"); + return CAST_ENGINE_ERROR; + } + sptr impl; + int32_t ret = proxy_->CreateMirrorPlayer(impl); + CHECK_AND_RETURN_RET_LOG(ret != CAST_ENGINE_SUCCESS, ret, "CastEngine Errors"); + if (!impl) { + return CAST_ENGINE_ERROR; + } + + auto player = std::make_shared(impl); + if (!player) { + CLOGE("Failed to malloc mirror player"); + return ERR_NO_MEMORY; + } + mirrorPlayer = player; + return ret; +} + +int32_t CastSession::CreateStreamPlayer(std::shared_ptr &streamPlayer) +{ + if (!proxy_) { + CLOGE("proxy_ is null"); + return CAST_ENGINE_ERROR; + } + sptr streamPlayerIpc; + int32_t ret = proxy_->CreateStreamPlayer(streamPlayerIpc); + CHECK_AND_RETURN_RET_LOG(ret != CAST_ENGINE_SUCCESS, ret, "CastEngine Errors"); + if (!streamPlayerIpc) { + return CAST_ENGINE_ERROR; + } + + auto player = std::make_shared(streamPlayerIpc); + if (!player) { + CLOGE("Failed to malloc stream player"); + return ERR_NO_MEMORY; + } + streamPlayer = player; + return ret; +} + +int32_t CastSession::Release() +{ + return proxy_ ? proxy_->Release() : CAST_ENGINE_ERROR; +} + +int32_t CastSession::SetCastMode(CastMode mode, std::string &jsonParam) +{ + return proxy_ ? proxy_->SetCastMode(mode, jsonParam) : false; +} + +int32_t CastSession::NotifyEvent(EventId eventId, std::string &jsonParam) +{ + if (proxy_ != nullptr) { + proxy_->NotifyEvent(eventId, jsonParam); + return CAST_ENGINE_SUCCESS; + } + return CAST_ENGINE_ERROR; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/client/src/cast_session_impl_proxy.cpp b/client/src/cast_session_impl_proxy.cpp new file mode 100644 index 0000000..e885b6a --- /dev/null +++ b/client/src/cast_session_impl_proxy.cpp @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session implement proxy + * Author: zhangge + * Create: 2022-5-29 + */ + +#include "cast_session_impl_proxy.h" + +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-Session"); + +CastSessionImplProxy::~CastSessionImplProxy() +{ + CLOGI("Stop the client cast session proxy."); +} + +int32_t CastSessionImplProxy::RegisterListener(sptr listener) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteRemoteObject(listener->AsObject())) { + CLOGE("Failed to write cast session listener"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(REGISTER_LISTENER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when registering listener"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::UnregisterListener() +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(UNREGISTER_LISTENER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when unregistering listener"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::AddDevice(const CastRemoteDevice &remoteDevice) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteCastRemoteDevice(data, remoteDevice)) { + CLOGE("Failed to write the remote device"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(ADD_DEVICE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when adding device"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when adding device"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when adding device"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::RemoveDevice(const std::string &deviceId) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(deviceId)) { + CLOGE("Failed to write the the device id"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(REMOVE_DEVICE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when removing device"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when removing device"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when removing device"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::StartAuth(const AuthInfo &authInfo) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return false; + } + if (!WriteAuthInfo(data, authInfo)) { + CLOGE("Failed to write auth info"); + return false; + } + + int32_t ret = Remote()->SendRequest(START_AUTH, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when starting auth"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when starting auth"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when starting auth"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::GetSessionId(std::string &sessionId) +{ + MessageParcel data, reply; + MessageOption option; + + sessionId = std::string{}; + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(GET_SESSION_ID, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when getting session id"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when getting session id"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + sessionId = reply.ReadString(); + + return errorCode; +} + +int32_t CastSessionImplProxy::GetDeviceState(const std::string &deviceId, DeviceState &deviceState) +{ + MessageParcel data, reply; + MessageOption option; + + deviceState = DeviceState::DISCONNECTED; + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(deviceId)) { + CLOGE("Failed to write the the device id"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(GET_DEVICE_STATE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when getting device state"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when getting device state"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when getting device state"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + int state = reply.ReadInt32(); + if (IsDeviceState(state)) { + deviceState = static_cast(state); + } + + return errorCode; +} + +int32_t CastSessionImplProxy::SetSessionProperty(const CastSessionProperty &property) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteCastSessionProperty(data, property)) { + CLOGE("Failed to write the property"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_SESSION_PROPERTY, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting session property"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting session property"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::CreateMirrorPlayer(sptr &mirrorPlayer) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(CREAT_MIRROR_PLAYER, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when creating mirror player"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when creating mirror player"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + auto object = reply.ReadRemoteObject(); + if (!object) { + CLOGE("Failed to get the mirror player object"); + return CAST_ENGINE_ERROR; + } + mirrorPlayer = iface_cast(object); + + return errorCode; +} + +int32_t CastSessionImplProxy::CreateStreamPlayer(sptr &streamPlayer) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(CREAT_STREAM_PLAYER, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when creating stream player"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when creating stream player"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + auto object = reply.ReadRemoteObject(); + if (!object) { + CLOGE("Failed to get the cast session object"); + return CAST_ENGINE_ERROR; + } + streamPlayer = iface_cast(object); + + return errorCode; +} + +int32_t CastSessionImplProxy::Release() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(RELEASE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when releasing the cast session"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when releasing the cast session"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::SetCastMode(CastMode mode, std::string &jsonParam) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(static_cast(mode))) { + CLOGE("Failed to write cast mode"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(jsonParam)) { + CLOGE("Failed to write json param"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(SET_CAST_MODE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when set cast mode"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionImplProxy::NotifyEvent(EventId eventId, std::string &jsonParam) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(static_cast(eventId))) { + CLOGE("Failed to write event id"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(jsonParam)) { + CLOGE("Failed to write json param"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(NOTIFY_EVENT, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when notify event"); + return CAST_ENGINE_ERROR; + } + return CAST_ENGINE_SUCCESS; +} + +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/cast_session_listener_impl_stub.cpp b/client/src/cast_session_listener_impl_stub.cpp new file mode 100644 index 0000000..6236034 --- /dev/null +++ b/client/src/cast_session_listener_impl_stub.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session listener implement stub. + * Author: zhangge + * Create: 2022-6-15 + */ + +#include "cast_session_listener_impl_stub.h" + +#include "cast_engine_common_helper.h" +#include "cast_stub_helper.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-SessionListener"); + +int CastSessionListenerImplStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + RETRUEN_IF_WRONG_TASK(code, data, reply, option); + return EXECUTE_SINGLE_STUB_TASK(code, data, reply); +} + +CastSessionListenerImplStub::CastSessionListenerImplStub(std::shared_ptr userListener_) + : userListener_(userListener_) +{ + FILL_SINGLE_STUB_TASK(ON_DEVICE_STATE, &CastSessionListenerImplStub::DoOnDeviceStateTask); + FILL_SINGLE_STUB_TASK(ON_EVENT, &CastSessionListenerImplStub::DoOnEventTask); +} + +int32_t CastSessionListenerImplStub::DoOnDeviceStateTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + auto stateInfo = ReadDeviceStateInfo(data); + if (stateInfo == nullptr) { + CLOGE("sate info is null"); + return ERR_NULL_OBJECT; + } + userListener_->OnDeviceState(*stateInfo); + + return ERR_NONE; +} + +int32_t CastSessionListenerImplStub::DoOnEventTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t eventId; + std::string param; + if (!ReadEvent(data, eventId, param)) { + CLOGE("read event failed"); + return ERR_NULL_OBJECT; + } + userListener_->OnEvent(static_cast(eventId), param); + + return ERR_NONE; +} + +void CastSessionListenerImplStub::OnDeviceState(const DeviceStateInfo &stateInfo) +{ + static_cast(stateInfo); +} + +void CastSessionListenerImplStub::OnEvent(const EventId &eventId, const std::string &jsonParam) +{ + static_cast(eventId); + static_cast(jsonParam); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/cast_session_manager.cpp b/client/src/cast_session_manager.cpp new file mode 100644 index 0000000..bcae060 --- /dev/null +++ b/client/src/cast_session_manager.cpp @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: implement the cast session manager + * Author: zhangge + * Create: 2022-06-15 + */ + +#include + +#include "cast_session_manager.h" + +#include + +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_engine_service_load_callback.h" +#include "cast_session_manager_adaptor.h" +#include "cast_session_manager_service_proxy.h" +#include "i_cast_session.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-SessionManager"); + +CastSessionManager::CastSessionManager() +{ + CLOGI("in"); +} + +CastSessionManager &CastSessionManager::GetInstance() +{ + static CastSessionManager instance {}; + return instance; +} + +std::shared_ptr CastSessionManager::GetAdaptor() +{ + CLOGI("in"); + std::lock_guard lock(mutex_); + if (adaptor_) { + return adaptor_; + } + + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + CLOGE("Failed to get SA manager"); + return nullptr; + } + sptr loadCallback = new (std::nothrow) CastEngineServiceLoadCallback(); + if (loadCallback == nullptr) { + CLOGE("Failed to new object"); + return nullptr; + } + + auto result = samgr->LoadSystemAbility(CAST_ENGINE_SA_ID, loadCallback); + if (result != ERR_OK) { + CLOGE("systemAbilityId: %d load failed, result code: %d", CAST_ENGINE_SA_ID, result); + return nullptr; + } + + constexpr int32_t sleepTimeMs = 30; + constexpr int32_t retryTimes = 150; // The service startup timeout interval is 4s. + int32_t retryTime = 0; + + sptr object; + while ((object = samgr->CheckSystemAbility(CAST_ENGINE_SA_ID)) == nullptr && (retryTime < retryTimes)) { + std::this_thread::sleep_for(std::chrono::milliseconds(sleepTimeMs)); + retryTime++; + } + if (object == nullptr) { + CLOGE("Failed to get cast engine manager"); + return nullptr; + } + + auto proxy = iface_cast(object); + adaptor_ = std::make_shared(proxy); + return adaptor_; +} + +int32_t CastSessionManager::RegisterListener(std::shared_ptr listener) +{ + CLOGI("in"); + if (listener == nullptr) { + CLOGE("Failed to init due to the null listener"); + return CAST_ENGINE_ERROR; + } + auto adaptor = GetAdaptor(); + if (!adaptor) { + return CAST_ENGINE_ERROR; + } + sptr deathRecipient( + new (std::nothrow) CastEngineServiceDeathRecipient(listener)); + if (!deathRecipient) { + CLOGE("Death recipient malloc failed"); + return CAST_ENGINE_ERROR; + } + if (adaptor->RegisterListener(listener, deathRecipient) == CAST_ENGINE_SUCCESS) { + std::lock_guard lock(mutex_); + deathRecipient_ = deathRecipient; + return CAST_ENGINE_SUCCESS; + } + return CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::UnregisterListener() +{ + CLOGI("in"); + ReleaseServiceDeathRecipient(); + auto adaptor = GetAdaptor(); + int32_t ret = adaptor ? adaptor->UnregisterListener() : CAST_ENGINE_ERROR; + std::lock_guard lock(mutex_); + adaptor_ = nullptr; + return ret; +} + +int32_t CastSessionManager::Release() +{ + CLOGI("in"); + ReleaseServiceDeathRecipient(); + auto adaptor = GetAdaptor(); + int32_t ret = adaptor ? adaptor->Release() : CAST_ENGINE_ERROR; + std::lock_guard lock(mutex_); + adaptor_ = nullptr; + return ret; +} + +int32_t CastSessionManager::SetLocalDevice(const CastLocalDevice &localDevice) +{ + CLOGI("in"); + if (localDevice.deviceId.empty()) { + CLOGE("Local device id is null"); + return CAST_ENGINE_ERROR; + } + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->SetLocalDevice(localDevice) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::CreateCastSession(const CastSessionProperty &property, + std::shared_ptr &castSession) +{ + CLOGI("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->CreateCastSession(property, castSession) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::SetSinkSessionCapacity(int sessionCapacity) +{ + CLOGD("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->SetSinkSessionCapacity(sessionCapacity) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::StartDiscovery(int protocols) +{ + CLOGD("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->StartDiscovery(protocols) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::SetDiscoverable(bool enable) +{ + CLOGI("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->SetDiscoverable(enable) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::StopDiscovery() +{ + CLOGI("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->StopDiscovery() : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManager::GetCastSession(std::string sessionId, std::shared_ptr &castSession) +{ + CLOGI("in"); + auto adaptor = GetAdaptor(); + return adaptor ? adaptor->GetCastSession(sessionId, castSession) : CAST_ENGINE_ERROR; +} + +void CastSessionManager::ReleaseClientResources() +{ + CLOGD("Release client resources"); + std::lock_guard lock(mutex_); + std::shared_ptr listener; + { + if (!!deathRecipient_) { + listener = deathRecipient_->GetListener(); + } + deathRecipient_ = nullptr; + adaptor_ = nullptr; + } + if (listener) { + listener->OnServiceDied(); + } else { + CLOGE("Report is nullptr"); + } +} + +void CastSessionManager::ReleaseServiceDeathRecipient() +{ + std::lock_guard lock(mutex_); + deathRecipient_ = nullptr; +} + +void CastSessionManager::CastEngineServiceDeathRecipient::OnRemoteDied(const wptr &object) +{ + CLOGE("Service died, need release resources"); + CastSessionManager::GetInstance().ReleaseClientResources(); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/cast_session_manager_adaptor.cpp b/client/src/cast_session_manager_adaptor.cpp new file mode 100644 index 0000000..051f55d --- /dev/null +++ b/client/src/cast_session_manager_adaptor.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager adaptor. + * Author: zhangge + * Create: 2022-5-29 + */ + +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_session_manager_adaptor.h" +#include "cast_service_listener_impl_stub.h" +#include "cast_session.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-ManagerAdaptor"); + +CastSessionManagerAdaptor::~CastSessionManagerAdaptor() +{ + CLOGD("destructor in"); + UnsubscribeDeathRecipient(); +} + +int32_t CastSessionManagerAdaptor::RegisterListener(std::shared_ptr listener, + sptr deathRecipient) +{ + sptr impl = new (std::nothrow) CastServiceListenerImplStub(listener); + if (impl == nullptr) { + CLOGE("Failed to malloc service listener"); + return CAST_ENGINE_ERROR; + } + auto object = proxy_ ? proxy_->GetSessionManagerService() : nullptr; + if (!object) { + CLOGW("Failed to get session manager service"); + return CAST_ENGINE_ERROR; + } + int32_t ret = proxy_ ? proxy_->RegisterListener(impl) : CAST_ENGINE_ERROR; + if (ret != CAST_ENGINE_SUCCESS) { + return ret; + } + if (object->AddDeathRecipient(deathRecipient)) { + std::lock_guard lock(mutex_); + deathRecipient_ = deathRecipient; + remote_ = object; + } else { + CLOGE("Add cast engine service death recipient failed"); + } + + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerAdaptor::UnregisterListener() +{ + UnsubscribeDeathRecipient(); + return proxy_ ? proxy_->UnregisterListener() : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::Release() +{ + UnsubscribeDeathRecipient(); + return proxy_ ? proxy_->Release() : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::SetLocalDevice(const CastLocalDevice &localDevice) +{ + return proxy_ ? proxy_->SetLocalDevice(localDevice) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::CreateCastSession(const CastSessionProperty &property, + std::shared_ptr &castSession) +{ + if (!proxy_) { + CLOGE("proxy is null"); + return CAST_ENGINE_ERROR; + } + sptr impl; + int32_t ret = proxy_->CreateCastSession(property, impl); + CHECK_AND_RETURN_RET_LOG(ret != CAST_ENGINE_SUCCESS, ret, "CastEngine Errors"); + if (impl == nullptr) { + CLOGE("cast session is NULL"); + return CAST_ENGINE_ERROR; + } + + auto session = std::make_shared(impl); + if (!session) { + CLOGE("Failed to malloc cast session"); + return ERR_NO_MEMORY; + } + std::string sessionId{}; + impl->GetSessionId(sessionId); + session->SetSessionId(sessionId); + castSession = session; + + return ret; +} + +int32_t CastSessionManagerAdaptor::SetSinkSessionCapacity(int sessionCapacity) +{ + return proxy_ ? proxy_->SetSinkSessionCapacity(sessionCapacity) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::StartDiscovery(int protocols) +{ + return proxy_ ? proxy_->StartDiscovery(protocols) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::SetDiscoverable(bool enable) +{ + return proxy_ ? proxy_->SetDiscoverable(enable) : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::StopDiscovery() +{ + return proxy_ ? proxy_->StopDiscovery() : CAST_ENGINE_ERROR; +} + +int32_t CastSessionManagerAdaptor::GetCastSession(std::string sessionId, std::shared_ptr &castSession) +{ + sptr impl; + int32_t ret = proxy_->GetCastSession(sessionId, impl); + CHECK_AND_RETURN_RET_LOG(ret != CAST_ENGINE_SUCCESS, ret, "CastEngine Errors"); + if (impl == nullptr) { + CLOGE("cast session is NULL"); + return CAST_ENGINE_ERROR; + } + + auto session = std::make_shared(impl); + if (!session) { + CLOGE("Failed to malloc cast session"); + return CAST_ENGINE_ERROR; + } + std::string id{}; + impl->GetSessionId(id); + session->SetSessionId(id); + castSession = session; + + return ret; +} + +void CastSessionManagerAdaptor::UnsubscribeDeathRecipient() +{ + std::lock_guard lock(mutex_); + if (!deathRecipient_) { + CLOGE("deathRecipient is null"); + return; + } + sptr remote = remote_.promote(); + if (!!remote) { + remote->RemoveDeathRecipient(deathRecipient_); + } + deathRecipient_ = nullptr; + CLOGD("Unsubscribe Death Recipient Success"); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/cast_session_manager_service_proxy.cpp b/client/src/cast_session_manager_service_proxy.cpp new file mode 100644 index 0000000..a6d44c7 --- /dev/null +++ b/client/src/cast_session_manager_service_proxy.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service proxy + * Author: zhangge + * Create: 2022-5-29 + */ + +#include "cast_engine_errors.h" +#include "cast_session_manager_service_proxy.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-Manager"); + +int32_t CastSessionManagerServiceProxy::RegisterListener(sptr listener) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteRemoteObject(listener->AsObject())) { + CLOGE("Failed to write cast service listener"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(REGISTER_LISTENER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when initing the cast service"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::UnregisterListener() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + int32_t ret = Remote()->SendRequest(UNREGISTER_LISTENER, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when unregistering listener"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when unregistering listener"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::Release() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + int32_t ret = Remote()->SendRequest(RELEASE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when Releasing the cast service"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when Releasing the cast service"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::SetLocalDevice(const CastLocalDevice &localDevice) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteCastLocalDevice(data, localDevice)) { + CLOGE("Failed to write cast local device"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_LOCAL_DEVICE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting local device"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when setting local device"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting local device"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::CreateCastSession(const CastSessionProperty &property, + sptr &castSession) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteCastSessionProperty(data, property)) { + CLOGE("Failed to write cast session property"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(CREATE_CAST_SESSION, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when creating cast session"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when creating cast session"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when creating cast session"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + auto object = reply.ReadRemoteObject(); + if (object == nullptr) { + CLOGE("Failed to get the cast session object"); + return CAST_ENGINE_ERROR; + } + castSession = iface_cast(object); + + return errorCode; +} + +int32_t CastSessionManagerServiceProxy::SetSinkSessionCapacity(int sessionCapacity) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(sessionCapacity)) { + CLOGE("Failed to write the session capacity"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_SINK_SESSION_CAPACITY, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting sink session capacity"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting sink session capacity"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::StartDiscovery(int protocols) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(protocols)) { + CLOGE("Failed to write the protocol type"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(START_DISCOVERY, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when starting discovery"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when starting discovery"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when starting discovery"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::SetDiscoverable(bool enable) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteBool(enable)) { + CLOGE("Failed to write discoverable value"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_DISCOVERABLE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting discoverable"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting discoverable"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::StopDiscovery() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(STOP_DISCOVERY, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting discoverable"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting discoverable"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CastSessionManagerServiceProxy::GetCastSession(std::string sessionId, sptr &castSession) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(sessionId)) { + CLOGE("Failed to write session ID"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_CAST_SESSION, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get cast session"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + auto object = reply.ReadRemoteObject(); + if (object == nullptr) { + CLOGE("Failed to get the cast session object"); + return CAST_ENGINE_ERROR; + } + castSession = iface_cast(object); + + return errorCode; +} + +sptr CastSessionManagerServiceProxy::GetSessionManagerService() +{ + return this->AsObject(); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/mirror_player.cpp b/client/src/mirror_player.cpp new file mode 100644 index 0000000..43dcdf7 --- /dev/null +++ b/client/src/mirror_player.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast mirror player function realization. + * Author: zhangjingnan + * Create: 2023-05-27 + */ + +#include "mirror_player.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "surface_utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-MirrorPlayer"); + +MirrorPlayer::~MirrorPlayer() +{ + CLOGI("Stop the client mirror player."); +} + +int32_t MirrorPlayer::Play(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("The device id is null"); + return ERR_INVALID_PARAM; + } + return proxy_ ? proxy_->Play(deviceId) : CAST_ENGINE_ERROR; +} + +int32_t MirrorPlayer::Pause(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("The device id is null"); + return ERR_INVALID_PARAM; + } + return proxy_ ? proxy_->Pause(deviceId) : CAST_ENGINE_ERROR; +} + +int32_t MirrorPlayer::SetSurface(const std::string &surfaceId) +{ + errno = 0; + uint64_t surfaceUniqueId = static_cast(std::strtoll(surfaceId.c_str(), nullptr, 10)); + if (errno == ERANGE) { + return ERR_INVALID_PARAM; + } + + sptr surface = SurfaceUtils::GetInstance()->GetSurface(surfaceUniqueId); + if (!surface) { + CLOGE("surface is null, surface uniqueId %llu", surfaceUniqueId); + return CAST_ENGINE_ERROR; + } + sptr producer = surface->GetProducer(); + if (!producer) { + CLOGE("producer is null"); + return CAST_ENGINE_ERROR; + } + return proxy_ ? proxy_->SetSurface(producer) : CAST_ENGINE_ERROR; +} + +int32_t MirrorPlayer::DeliverInputEvent(OHRemoteControlEvent event) +{ + return proxy_ ? proxy_->DeliverInputEvent(event) : CAST_ENGINE_ERROR; +} + +int32_t MirrorPlayer::Release() +{ + return proxy_ ? proxy_->Release() : CAST_ENGINE_ERROR; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/client/src/mirror_player_impl_proxy.cpp b/client/src/mirror_player_impl_proxy.cpp new file mode 100644 index 0000000..59076af --- /dev/null +++ b/client/src/mirror_player_impl_proxy.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply mirror player implement proxy + * Author: zhangjingnan + * Create: 2023-5-27 + */ + +#include "mirror_player_impl_proxy.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-MirrorPlayer"); + +MirrorPlayerImplProxy::~MirrorPlayerImplProxy() +{ + CLOGI("Stop the client mirror player proxy."); +} + +int32_t MirrorPlayerImplProxy::Play(const std::string &deviceId) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(deviceId)) { + CLOGE("Failed to write the the device id"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(PLAY, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when executing the playing action"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when executing the playing action"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when executing the playing action"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t MirrorPlayerImplProxy::Pause(const std::string &deviceId) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteString(deviceId)) { + CLOGE("Failed to write the the device id"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(PAUSE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when executing the pausing action"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when executing the pausing action"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when executing the pausing action"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t MirrorPlayerImplProxy::SetSurface(sptr producer) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteRemoteObject(producer->AsObject())) { + CLOGE("Failed to write surface producer"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_SURFACE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting surface"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting surface"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t MirrorPlayerImplProxy::DeliverInputEvent(const OHRemoteControlEvent &event) +{ + MessageParcel data, reply; + MessageOption option; + + CLOGD("In, eventType:%d", static_cast(event.eventType)); + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteRemoteControlEvent(data, event)) { + CLOGE("Failed to write the remote control event"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(DELIVER_INPUT_EVENT, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when deliver input event"); + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when deliver input event"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when deliver input event"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t MirrorPlayerImplProxy::Release() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(RELEASE, data, reply, option); + if (ret == ERR_UNKNOWN_TRANSACTION) { + CLOGE("No permission when setting surface"); + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting surface"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/stream_player.cpp b/client/src/stream_player.cpp new file mode 100644 index 0000000..c34674b --- /dev/null +++ b/client/src/stream_player.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Stream Player function realization. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#include "stream_player.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "stream_player_listener_impl_stub.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-StreamPlayer"); + +StreamPlayer::~StreamPlayer() +{ + CLOGD("destructor in"); +} + +int32_t StreamPlayer::RegisterListener(std::shared_ptr listener) +{ + if (listener == nullptr) { + CLOGE("listener is null"); + return ERR_INVALID_PARAM; + } + sptr listenerStub = new (std::nothrow) StreamPlayerListenerImplStub(listener); + if (listenerStub == nullptr) { + CLOGE("Failed to new a stream player listener"); + return CAST_ENGINE_ERROR; + } + + return proxy_ ? proxy_->RegisterListener(listenerStub) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::UnregisterListener() +{ + return proxy_ ? proxy_->UnregisterListener() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::SetSurface(const std::string &surfaceId) +{ + errno = 0; + uint64_t surfaceUniqueId = static_cast(std::strtoll(surfaceId.c_str(), nullptr, 10)); + if (errno == ERANGE) { + return ERR_INVALID_PARAM; + } + + sptr surface = SurfaceUtils::GetInstance()->GetSurface(surfaceUniqueId); + if (!surface) { + CLOGE("surface is null, surface uniqueId %llu", surfaceUniqueId); + return CAST_ENGINE_ERROR; + } + sptr producer = surface->GetProducer(); + if (!producer) { + CLOGE("producer is null"); + return CAST_ENGINE_ERROR; + } + return proxy_ ? proxy_->SetSurface(producer) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Load(const MediaInfo &mediaInfo) +{ + return proxy_ ? proxy_->Load(mediaInfo) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Play(const MediaInfo &mediaInfo) +{ + return proxy_ ? proxy_->Play(mediaInfo) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Play(int index) +{ + return proxy_ ? proxy_->Play(index) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Play() +{ + return proxy_ ? proxy_->Play() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Pause() +{ + return proxy_ ? proxy_->Pause() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Stop() +{ + return proxy_ ? proxy_->Stop() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Next() +{ + return proxy_ ? proxy_->Next() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Previous() +{ + return proxy_ ? proxy_->Previous() : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Seek(int position) +{ + return proxy_ ? proxy_->Seek(position) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::FastForward(int delta) +{ + return proxy_ ? proxy_->FastForward(delta) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::FastRewind(int delta) +{ + return proxy_ ? proxy_->FastRewind(delta) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::SetVolume(int volume) +{ + return proxy_ ? proxy_->SetVolume(volume) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::SetLoopMode(const LoopMode mode) +{ + return proxy_ ? proxy_->SetLoopMode(mode) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::SetSpeed(const PlaybackSpeed speed) +{ + return proxy_ ? proxy_->SetSpeed(speed) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetPlayerStatus(PlayerStates &playerStates) +{ + return proxy_ ? proxy_->GetPlayerStatus(playerStates) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetPosition(int &position) +{ + return proxy_ ? proxy_->GetPosition(position) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetDuration(int &duration) +{ + return proxy_ ? proxy_->GetDuration(duration) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetVolume(int &volume, int &maxVolume) +{ + return proxy_ ? proxy_->GetVolume(volume, maxVolume) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetLoopMode(LoopMode &loopMode) +{ + return proxy_ ? proxy_->GetLoopMode(loopMode) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetPlaySpeed(PlaybackSpeed &playbackSpeed) +{ + return proxy_ ? proxy_->GetPlaySpeed(playbackSpeed) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) +{ + return proxy_ ? proxy_->GetMediaInfoHolder(mediaInfoHolder) : CAST_ENGINE_ERROR; +} + +int32_t StreamPlayer::Release() +{ + return proxy_ ? proxy_->Release() : CAST_ENGINE_ERROR; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/client/src/stream_player_impl_proxy.cpp b/client/src/stream_player_impl_proxy.cpp new file mode 100644 index 0000000..1980c78 --- /dev/null +++ b/client/src/stream_player_impl_proxy.cpp @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player implement proxy realization. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#include "stream_player_impl_proxy.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-StreamPlayer"); + +StreamPlayerImplProxy::~StreamPlayerImplProxy() +{ + CLOGD("destructor in"); +} + +int32_t StreamPlayerImplProxy::RegisterListener(sptr listener) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteRemoteObject(listener->AsObject())) { + CLOGE("Failed to write stream player listener"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(REGISTER_LISTENER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when registering listener"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::UnregisterListener() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(UNREGISTER_LISTENER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when unregistering listener"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::SetSurface(sptr producer) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteRemoteObject(producer->AsObject())) { + CLOGE("Failed to write surface producer"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(SET_SURFACE, data, reply, option); + if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when setting surface"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when setting surface"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Load(const MediaInfo &mediaInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteMediaInfo(data, mediaInfo)) { + CLOGE("Failed to write the mediaInfo"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(LOAD, data, reply, option); + if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when load"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when load"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Play(const MediaInfo &mediaInfo) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!WriteMediaInfo(data, mediaInfo)) { + CLOGE("Failed to write the mediaInfo"); + return CAST_ENGINE_ERROR; + } + + int32_t ret = Remote()->SendRequest(START, data, reply, option); + if (ret == ERR_INVALID_DATA) { + CLOGE("Invalid parameter when play"); + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + CLOGE("Failed to send ipc request when play"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Play(int index) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(index)) { + CLOGE("Failed to write the index"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(PLAY_INDEX, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when play"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Pause() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(PAUSE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when pause"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Play() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(PLAY, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when resume"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Stop() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(STOP, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when stop"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Next() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(NEXT, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when stop"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Previous() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(PREVIOUS, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when stop"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::Seek(int position) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(position)) { + CLOGE("Failed to write the position"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(SEEK, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when seek"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::FastForward(int delta) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(delta)) { + CLOGE("Failed to write the delta"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(FAST_FORWARD, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when fastForward"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::FastRewind(int delta) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(delta)) { + CLOGE("Failed to write the delta"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(FAST_REWIND, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when fastRewind"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::SetVolume(int volume) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(volume)) { + CLOGE("Failed to write the position"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(SET_VOLUME, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when set volume"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::SetLoopMode(const LoopMode mode) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(static_cast(mode))) { + CLOGE("Failed to write the position"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(SET_LOOP_MODE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when set volume"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::SetSpeed(const PlaybackSpeed speed) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (!data.WriteInt32(static_cast(speed))) { + CLOGE("Failed to write the position"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(SET_SPEED, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when set volume"); + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StreamPlayerImplProxy::GetPlayerStatus(PlayerStates &playerStates) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + playerStates = PlayerStates::PLAYER_STATE_ERROR; + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_PLAYER_STATUS, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get player status"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + playerStates = static_cast(reply.ReadInt32()); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetPosition(int &position) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_POSITION, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get position"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + position = reply.ReadInt32(); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetDuration(int &duration) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_DURATION, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get duration"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + duration = reply.ReadInt32(); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetVolume(int &volume, int &maxVolume) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_VOLUME, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get duration"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + volume = reply.ReadInt32(); + maxVolume = reply.ReadInt32(); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetLoopMode(LoopMode &loopMode) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + loopMode = LoopMode::LOOP_MODE_LIST; + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_LOOP_MODE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get duration"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + loopMode = static_cast(reply.ReadInt32()); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetPlaySpeed(PlaybackSpeed &playbackSpeed) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + playbackSpeed = PlaybackSpeed::SPEED_FORWARD_1_00_X; + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_PLAY_SPEED, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get duration"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + playbackSpeed = static_cast(reply.ReadInt32()); + + return errorCode; +} + +int32_t StreamPlayerImplProxy::GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return CAST_ENGINE_ERROR; + } + if (Remote()->SendRequest(GET_MEDIA_INFO_HOLDER, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when get duration"); + return CAST_ENGINE_ERROR; + } + + int32_t errorCode = reply.ReadInt32(); + CHECK_AND_RETURN_RET_LOG(errorCode != CAST_ENGINE_SUCCESS, errorCode, "CastEngine Errors"); + auto mediaInfos = ReadMediaInfoHolder(reply); + if (mediaInfos == nullptr) { + CLOGE("GetMediaInfoHolder, mediaInfoHolder is null"); + return CAST_ENGINE_ERROR; + } + mediaInfoHolder = *mediaInfos; + + return errorCode; +} + +int32_t StreamPlayerImplProxy::Release() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return false; + } + if (Remote()->SendRequest(RELEASE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when Releasing stream player"); + return false; + } + + return reply.ReadInt32(); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/client/src/stream_player_listener_impl_stub.cpp b/client/src/stream_player_listener_impl_stub.cpp new file mode 100644 index 0000000..367f51c --- /dev/null +++ b/client/src/stream_player_listener_impl_stub.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player listener implement stub realization. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#include "stream_player_listener_impl_stub.h" +#include "cast_engine_common_helper.h" +#include "cast_stub_helper.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Client-StreamPlayerListener"); + +int StreamPlayerListenerImplStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + RETRUEN_IF_WRONG_TASK(code, data, reply, option); + if (userListener_ == nullptr) { + CLOGE("userListener_ is null, code:%{public}d", code); + return ERR_NULL_OBJECT; + } + return EXECUTE_SINGLE_STUB_TASK(code, data, reply); +} + +StreamPlayerListenerImplStub::StreamPlayerListenerImplStub(std::shared_ptr userListener) + : userListener_(userListener) +{ + FILL_SINGLE_STUB_TASK(ON_PLAYER_STATUS_CHANGED, &StreamPlayerListenerImplStub::DoOnStateChangedTask); + FILL_SINGLE_STUB_TASK(ON_POSITION_CHANGED, &StreamPlayerListenerImplStub::DoOnPositionChangedTask); + FILL_SINGLE_STUB_TASK(ON_MEDIA_ITEM_CHANGED, &StreamPlayerListenerImplStub::DoOnMediaItemChangedTask); + FILL_SINGLE_STUB_TASK(ON_VOLUME_CHANGED, &StreamPlayerListenerImplStub::DoOnVolumeChangedTask); + FILL_SINGLE_STUB_TASK(ON_REPEAT_MODE_CHANGED, &StreamPlayerListenerImplStub::DoOnLoopModeChangedTask); + FILL_SINGLE_STUB_TASK(ON_PLAY_SPEED_CHANGED, &StreamPlayerListenerImplStub::DoOnPlaySpeedChangedTask); + FILL_SINGLE_STUB_TASK(ON_PLAYER_ERROR, &StreamPlayerListenerImplStub::DoOnPlayerErrorTask); + FILL_SINGLE_STUB_TASK(ON_VIDEO_SIZE_CHANGED, &StreamPlayerListenerImplStub::DoOnVideoSizeChangedTask); + FILL_SINGLE_STUB_TASK(ON_NEXT_REQUEST, &StreamPlayerListenerImplStub::DoOnNextRequestTask); + FILL_SINGLE_STUB_TASK(ON_PREVIOUS_REQUEST, &StreamPlayerListenerImplStub::DoOnPreviousRequestTask); + FILL_SINGLE_STUB_TASK(ON_SEEK_DONE, &StreamPlayerListenerImplStub::DoOnSeekDoneTask); + FILL_SINGLE_STUB_TASK(ON_END_OF_STREAM, &StreamPlayerListenerImplStub::DoOnEndOfStreamTask); + FILL_SINGLE_STUB_TASK(ON_PLAY_REQUEST, &StreamPlayerListenerImplStub::DoOnPlayRequestTask); +} + +StreamPlayerListenerImplStub::~StreamPlayerListenerImplStub() +{ + userListener_ = nullptr; + CLOGE("destructor in"); +} + +int32_t StreamPlayerListenerImplStub::DoOnStateChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t state = data.ReadInt32(); + bool isPlayWhenReady = data.ReadBool(); + PlayerStates playbackState = static_cast(state); + userListener_->OnStateChanged(playbackState, isPlayWhenReady); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnPositionChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t position = data.ReadInt32(); + int32_t bufferPosition = data.ReadInt32(); + int32_t duration = data.ReadInt32(); + userListener_->OnPositionChanged(position, bufferPosition, duration); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnMediaItemChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + auto mediaInfo = ReadMediaInfo(data); + if (mediaInfo == nullptr) { + CLOGE("DoOnMediaItemChangedTask,mediaInfo is null"); + return ERR_NULL_OBJECT; + } + userListener_->OnMediaItemChanged(*mediaInfo); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnVolumeChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t volume = data.ReadInt32(); + int32_t maxVolume = data.ReadInt32(); + userListener_->OnVolumeChanged(volume, maxVolume); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnLoopModeChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t mode = data.ReadInt32(); + LoopMode loopMode = static_cast(mode); + userListener_->OnLoopModeChanged(loopMode); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnPlaySpeedChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t speed = data.ReadInt32(); + PlaybackSpeed speedMode = static_cast(speed); + userListener_->OnPlaySpeedChanged(speedMode); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnPlayerErrorTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t errorCode = data.ReadInt32(); + std::string errorMsg = data.ReadString(); + userListener_->OnPlayerError(errorCode, errorMsg); + + return ERR_NONE; +} +int32_t StreamPlayerListenerImplStub::DoOnVideoSizeChangedTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t width = data.ReadInt32(); + int32_t height = data.ReadInt32(); + userListener_->OnVideoSizeChanged(width, height); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnNextRequestTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(data); + static_cast(reply); + userListener_->OnNextRequest(); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnPreviousRequestTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(data); + static_cast(reply); + userListener_->OnPreviousRequest(); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnSeekDoneTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t position = data.ReadInt32(); + userListener_->OnSeekDone(position); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnEndOfStreamTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + int32_t isLooping = data.ReadInt32(); + userListener_->OnEndOfStream(isLooping); + + return ERR_NONE; +} + +int32_t StreamPlayerListenerImplStub::DoOnPlayRequestTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + auto mediaInfo = ReadMediaInfo(data); + if (mediaInfo == nullptr) { + CLOGE("DoOnPlayRequestTask, mediaInfo is null"); + return ERR_NULL_OBJECT; + } + userListener_->OnPlayRequest(*mediaInfo); + + return ERR_NONE; +} + +void StreamPlayerListenerImplStub::OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) +{ + static_cast(playbackState); + static_cast(isPlayWhenReady); +} + +void StreamPlayerListenerImplStub::OnPositionChanged(int position, int bufferPosition, int duration) +{ + static_cast(position); + static_cast(bufferPosition); + static_cast(duration); +} + +void StreamPlayerListenerImplStub::OnMediaItemChanged(const MediaInfo &mediaInfo) +{ + static_cast(mediaInfo); +} + +void StreamPlayerListenerImplStub::OnVolumeChanged(int volume, int maxVolume) +{ + static_cast(volume); + static_cast(maxVolume); +} + +void StreamPlayerListenerImplStub::OnLoopModeChanged(const LoopMode loopMode) +{ + static_cast(loopMode); +} + +void StreamPlayerListenerImplStub::OnPlaySpeedChanged(const PlaybackSpeed speed) +{ + static_cast(speed); +} + +void StreamPlayerListenerImplStub::OnPlayerError(int errorCode, const std::string &errorMsg) +{ + static_cast(errorCode); + static_cast(errorMsg); +} + +void StreamPlayerListenerImplStub::OnVideoSizeChanged(int width, int height) +{ + static_cast(width); + static_cast(height); +} + +void StreamPlayerListenerImplStub::OnNextRequest() +{ +} + +void StreamPlayerListenerImplStub::OnPreviousRequest() +{ +} + +void StreamPlayerListenerImplStub::OnSeekDone(int position) +{ + static_cast(position); +} + +void StreamPlayerListenerImplStub::OnEndOfStream(int isLooping) +{ + static_cast(isLooping); +} + +void StreamPlayerListenerImplStub::OnPlayRequest(const MediaInfo &mediaInfo) +{ + static_cast(mediaInfo); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/common/BUILD.gn b/common/BUILD.gn new file mode 100644 index 0000000..5dacef1 --- /dev/null +++ b/common/BUILD.gn @@ -0,0 +1,44 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_engine_common_private_config") { + include_dirs = [ "include/private" ] +} + +ohos_static_library("cast_engine_common_sources") { + sources = [ + "src/cast_engine_common_helper.cpp", + "src/cast_engine_dfx.cpp", + ] + + configs = [ + ":cast_engine_common_private_config", + "${cast_engine_root}:cast_engine_default_config", + ] + + include_dirs = [ + "//third_party/json/single_include/nlohmann", + ] + + public_configs = [ + ":cast_engine_common_private_config", + "${cast_engine_interfaces}/inner_api:cast_interfaces_config", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "ipc:ipc_core", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/common/include/private/cast_engine_common_helper.h b/common/include/private/cast_engine_common_helper.h new file mode 100644 index 0000000..01192e5 --- /dev/null +++ b/common/include/private/cast_engine_common_helper.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply a helper to write/read common cast engine structures through ipc + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_ENGINE_COMMON_HELPER_H +#define CAST_ENGINE_COMMON_HELPER_H + +#include "cast_engine_common.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +bool WriteCastRemoteDevice(Parcel &parcel, const CastRemoteDevice &device); +std::unique_ptr ReadCastRemoteDevice(Parcel &parcel); +bool ReadCastRemoteDevice(Parcel &parcel, CastRemoteDevice &device); + +bool WriteMediaInfo(MessageParcel &parcel, const MediaInfo &mediaInfo); +std::unique_ptr ReadMediaInfo(MessageParcel &parcel); + +bool WriteMediaInfoHolder(MessageParcel &parcel, const MediaInfoHolder &mediaInfoHolder); +std::unique_ptr ReadMediaInfoHolder(MessageParcel &parcel); + +bool WriteCastLocalDevice(Parcel &parcel, const CastLocalDevice &device); +std::unique_ptr ReadCastLocalDevice(Parcel &parcel); + +bool WriteCastSessionProperty(Parcel &parcel, const CastSessionProperty &property); +std::unique_ptr ReadCastSessionProperty(Parcel &parcel); + +bool WritePropertyContainer(Parcel &parcel, const PropertyContainer &device); +std::unique_ptr ReadPropertyContainer(Parcel &parcel); + +bool WriteAuthInfo(Parcel &parcel, const AuthInfo &authInfo); +std::unique_ptr ReadAuthInfo(Parcel &parcel); + +bool WriteRemoteControlEvent(Parcel &parcel, const OHRemoteControlEvent &event); +std::unique_ptr ReadRemoteControlEvent(Parcel &parcel); + +bool WriteDeviceStateInfo(Parcel &parcel, const DeviceStateInfo &stateInfo); +std::unique_ptr ReadDeviceStateInfo(Parcel &parcel); + +bool WriteEvent(Parcel &parcel, const EventId &eventId, const std::string &jsonParam); +bool ReadEvent(Parcel &parcel, int32_t &eventId, std::string &jsonParam); + +void SetDataCapacity(MessageParcel &parcel, const FileFdMap &fileList, uint32_t tokenSize); +bool WriteFileList(MessageParcel &parcel, const FileFdMap &fileList); +bool ReadFileList(MessageParcel &parcel, FileFdMap &fileList); + +bool WriteRcvFdFileMap(MessageParcel &parcel, const RcvFdFileMap &rcvFdFileMap); +bool ReadRcvFdFileMap(MessageParcel &parcel, RcvFdFileMap &rcvFdFileMap); +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/cast_engine_dfx.h b/common/include/private/cast_engine_dfx.h new file mode 100644 index 0000000..78124bd --- /dev/null +++ b/common/include/private/cast_engine_dfx.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast engine dfx. + * Author: wangxueshuang + * Create: 2023-06-05 + */ + +#ifndef CAST_ENGINE_DFX_H +#define CAST_ENGINE_DFX_H + +#include + +#include "json.hpp" + +namespace OHOS { +namespace CastEngine { +using nlohmann::json; + +class CastEngineDfx { +public: + static void WriteErrorEvent(int32_t errorCode); + static void SetStreamInfo(const std::string &streamInfoKey, const std::string &streamInfoValue); + static void SetLocalDeviceInfo(const std::string &localDeviceInfoKey, const std::string &localDeviceInfoValue); + static void SetRemoteDeviceInfo(const std::string &remoteDeviceInfoKey, const std::string &remoteDeviceInfoValue); + static void SetConnectInfo(const std::string &connectInfoKey, const std::string &connectInfoValue); + static std::string GetStreamInfo(); + static std::string GetLocalDeviceInfo(); + static std::string GetRemoteDeviceInfo(); + static std::string GetConnectInfo(); + static std::string GetSequentialId(); + static std::string GetBizPackageName(); + +private: + static json jsonSteamInfo_; + static json jsonLocalDeviceInfo_; + static json jsonRemoteDeviceInfo_; + static json jsonConnectInfo_; + static const std::string PACKAGE_NAME; + static const std::string SEQUENTIAL_ID_CHARS; + static const int SN_LENGTH = 32; + static const int SEQUENTIAL_ID_CHARS_LENGTH = 62; +}; + +// discovery fail error code +static const int32_t START_DISCOVERY_FAIL = 100; + +// connection fail error code +static const int32_t AUTHENTICATE_DEVICE_FAIL = 200; +static const int32_t SOURCE_CREATE_SESSION_SERVER_FAIL = 201; +static const int32_t SINK_CREATE_SESSION_SERVER_FAIL = 202; +static const int32_t OPEN_SESSION_FAIL = 203; +static const int32_t SEND_CONSULTION_DATA_FAIL = 204; + +// stream fail error code +static const int32_t PLAYER_INIT_FAIL = 300; + +static constexpr char CAST_ENGINE_DFX_DOMAIN_NAME[] = "CAST_ENGINE"; +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_DFX_H diff --git a/common/include/private/cast_engine_log.h b/common/include/private/cast_engine_log.h new file mode 100644 index 0000000..010f1a0 --- /dev/null +++ b/common/include/private/cast_engine_log.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Log format definitions. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_ENGINE_LOG_H +#define CAST_ENGINE_LOG_H + +#include "hilog/log_cpp.h" + +using OHOS::HiviewDFX::HiLog; +using OHOS::HiviewDFX::HiLogLabel; + +namespace OHOS { +namespace CastEngine { +inline constexpr unsigned int CASTPLUS_LOG_BEGIN = 0xD004600; +inline constexpr unsigned int CAST_ENGINE_LOG_ID = CASTPLUS_LOG_BEGIN + 0x01; +inline constexpr unsigned int CASTPLUS_LOG_END = CASTPLUS_LOG_BEGIN + 0x10; + +inline constexpr bool DEBUG = false; + +#define DEFINE_CAST_ENGINE_LABEL(name) \ + static constexpr HiLogLabel CAST_ENGINE_LABEL = { LOG_CORE, OHOS::CastEngine::CAST_ENGINE_LOG_ID, name } + +#define CLOGV(format, ...) \ + do { \ + if (DEBUG) { \ + (void)HiLog::Debug(CAST_ENGINE_LABEL, "[%{public}s:%{public}d]: " format, __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ + } while (0) +#define CLOGD(format, ...) \ + (void)HiLog::Debug(CAST_ENGINE_LABEL, "[%{public}s:%{public}d]: " format, __func__, __LINE__, ##__VA_ARGS__) +#define CLOGI(format, ...) \ + (void)HiLog::Info(CAST_ENGINE_LABEL, "[%{public}s:%{public}d]: " format, __func__, __LINE__, ##__VA_ARGS__) +#define CLOGW(format, ...) \ + (void)HiLog::Warn(CAST_ENGINE_LABEL, "[%{public}s:%{public}d]: " format, __func__, __LINE__, ##__VA_ARGS__) +#define CLOGE(format, ...) \ + (void)HiLog::Error(CAST_ENGINE_LABEL, "[%{public}s:%{public}d]: " format, __func__, __LINE__, ##__VA_ARGS__) + +#define CHECK_AND_RETURN_RET_LOG(cond, ret, fmt, ...) \ + do { \ + if (cond) { \ + CLOGE(fmt, ##__VA_ARGS__); \ + return ret; \ + } \ + } while (0) +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/common/include/private/cast_service_common.h b/common/include/private/cast_service_common.h new file mode 100644 index 0000000..981ea1a --- /dev/null +++ b/common/include/private/cast_service_common.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast engine service related common data stucture definitions. + * Author: zhangge + * Create: 2022-10-26 + */ + +#ifndef CAST_SERVICE_COMMON_H +#define CAST_SERVICE_COMMON_H + +#include + +#include "cast_engine_common.h" + +namespace OHOS { +namespace CastEngine { +struct CastInnerRemoteDevice { + std::string deviceId; + std::string deviceName; + DeviceType deviceType{ DeviceType::DEVICE_OTHERS }; + SubDeviceType subDeviceType{ SubDeviceType::SUB_DEVICE_DEFAULT }; + std::string ipAddress; + TriggerType triggerType{ TriggerType::UNSPEC_TAG }; + std::string authData; + int sessionId{ INVALID_ID }; + ChannelType channelType{ ChannelType::SOFT_BUS }; + const uint8_t *sessionKey{ nullptr }; + uint32_t sessionKeyLength{ 0 }; +}; + +inline constexpr char PKG_NAME[] = "CastEngineService"; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/cast_stub_helper.h b/common/include/private/cast_stub_helper.h new file mode 100644 index 0000000..9a3161f --- /dev/null +++ b/common/include/private/cast_stub_helper.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply a helper to define some methods for stub object. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_STUB_HELPER_H +#define CAST_STUB_HELPER_H + +#include +#include "cast_engine_log.h" +#include "iremote_stub.h" + +namespace OHOS { +namespace CastEngine { +#define DECLARE_STUB_TASK_MAP(className) \ +private: \ + using className##Func = int32_t (className::*)(MessageParcel &, MessageParcel &); \ + std::map taskMap_ + +#define FILL_SINGLE_STUB_TASK(id, func) taskMap_[id] = (func) + +#define RETURN_IF_WRONG_INTERFACE_TOKEN(data) \ + if (GetDescriptor() != (data).ReadInterfaceToken()) { \ + CLOGE("Invalid interface token"); \ + return ERR_FLATTEN_OBJECT; \ + } + +#define RETRUEN_IF_WRONG_TASK(code, data, reply, option) \ + do { \ + RETURN_IF_WRONG_INTERFACE_TOKEN(data); \ + if (taskMap_.count(code) == 0) { \ + CLOGE("Invalid code:%d", code); \ + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); \ + } \ + } while (0) + +#define EXECUTE_SINGLE_STUB_TASK(code, data, reply) (this->*taskMap_[code])(data, reply) +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/i_cast_service_listener_impl.h b/common/include/private/i_cast_service_listener_impl.h new file mode 100644 index 0000000..98f3f2a --- /dev/null +++ b/common/include/private/i_cast_service_listener_impl.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session service listener implement apis. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef I_CAST_SERVICE_LISTENER_IMPL_H +#define I_CAST_SERVICE_LISTENER_IMPL_H + +#include "i_cast_session_manager_listener.h" +#include "iremote_broker.h" +#include "i_cast_session_impl.h" + +namespace OHOS { +namespace CastEngine { +class ICastServiceListenerImpl : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.ICastServiceListenerImpl"); + + ICastServiceListenerImpl() = default; + ICastServiceListenerImpl(const ICastServiceListenerImpl &) = delete; + ICastServiceListenerImpl &operator=(const ICastServiceListenerImpl &) = delete; + ICastServiceListenerImpl(ICastServiceListenerImpl &&) = delete; + ICastServiceListenerImpl &operator=(ICastServiceListenerImpl &&) = delete; + ~ICastServiceListenerImpl() override = default; + + virtual void OnDeviceFound(const std::vector &deviceList) = 0; + virtual void OnDeviceOffline(const std::string &deviceId) = 0; + virtual void OnSessionCreated(const sptr &castSession) = 0; + virtual void OnServiceDied() = 0; + +protected: + enum { + ON_DEVICE_FOUND = 1, + ON_DEVICE_OFFLINE, + ON_SESSION_CREATE, + ON_SERVICE_DIE + }; +}; +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/common/include/private/i_cast_session_impl.h b/common/include/private/i_cast_session_impl.h new file mode 100644 index 0000000..31eb760 --- /dev/null +++ b/common/include/private/i_cast_session_impl.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session interface. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef I_CAST_SESSION_IMPL_H +#define I_CAST_SESSION_IMPL_H + +#include + +#include "cast_engine_common.h" +#include "cast_service_common.h" +#include "i_cast_session.h" +#include "i_cast_session_listener_impl.h" +#include "iremote_broker.h" +#include "oh_remote_control_event.h" +#include "surface_utils.h" +#include "i_stream_player_ipc.h" +#include "i_mirror_player_impl.h" + +namespace OHOS { +namespace CastEngine { +class ICastSessionImpl : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.ICastSessionImpl"); + + ICastSessionImpl() = default; + ICastSessionImpl(const ICastSessionImpl &) = delete; + ICastSessionImpl &operator=(const ICastSessionImpl &) = delete; + ICastSessionImpl(ICastSessionImpl &&) = delete; + ICastSessionImpl &operator=(ICastSessionImpl &&) = delete; + ~ICastSessionImpl() override = default; + + virtual int32_t RegisterListener(sptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t AddDevice(const CastRemoteDevice &remoteDevice) = 0; + virtual int32_t RemoveDevice(const std::string &deviceId) = 0; + virtual int32_t StartAuth(const AuthInfo &authInfo) = 0; + virtual int32_t GetSessionId(std::string &sessionId) = 0; + virtual int32_t GetDeviceState(const std::string &deviceId, DeviceState &deviceState) = 0; + virtual int32_t SetSessionProperty(const CastSessionProperty &property) = 0; + virtual int32_t CreateMirrorPlayer(sptr &mirrorPlayer) = 0; + virtual int32_t CreateStreamPlayer(sptr &streamPlayer) = 0; + virtual int32_t Release() = 0; + virtual int32_t NotifyEvent(EventId eventId, std::string &jsonParam) = 0; + virtual int32_t SetCastMode(CastMode mode, std::string &jsonParam) = 0; + virtual bool AddDevice(const CastInnerRemoteDevice &remoteDevice) + { + return false; + } + virtual bool ReleaseSessionResources(pid_t pid) + { + return false; + } + virtual void Stop() {} + +protected: + enum { + REGISTER_LISTENER = 1, + UNREGISTER_LISTENER, + ADD_DEVICE, + REMOVE_DEVICE, + START_AUTH, + GET_SESSION_ID, + GET_DEVICE_STATE, + SET_SESSION_PROPERTY, + CREAT_MIRROR_PLAYER, + CREAT_STREAM_PLAYER, + RELEASE, + NOTIFY_EVENT, + SET_CAST_MODE, + }; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/i_cast_session_listener_impl.h b/common/include/private/i_cast_session_listener_impl.h new file mode 100644 index 0000000..06bf7f4 --- /dev/null +++ b/common/include/private/i_cast_session_listener_impl.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast session listener implement interface. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef I_CAST_SESSION_LISTENER_IMPL_H +#define I_CAST_SESSION_LISTENER_IMPL_H + +#include "cast_engine_common.h" +#include "i_cast_session.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace CastEngine { +class ICastSessionListenerImpl : public IRemoteBroker, public ICastSessionListener { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.ICastSessionListenerImpl"); + ICastSessionListenerImpl() = default; + ICastSessionListenerImpl(const ICastSessionListenerImpl &) = delete; + ICastSessionListenerImpl &operator=(const ICastSessionListenerImpl &) = delete; + ICastSessionListenerImpl(ICastSessionListenerImpl &&) = delete; + ICastSessionListenerImpl &operator=(ICastSessionListenerImpl &&) = delete; + ~ICastSessionListenerImpl() override = default; + +protected: + enum { + ON_DEVICE_STATE = 1, + ON_EVENT + }; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/common/include/private/i_cast_session_manager_service.h b/common/include/private/i_cast_session_manager_service.h new file mode 100644 index 0000000..aa98440 --- /dev/null +++ b/common/include/private/i_cast_session_manager_service.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service base class. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef I_CAST_SESSION_MANAGER_SERVICE_H +#define I_CAST_SESSION_MANAGER_SERVICE_H + +#include "cast_engine_common.h" +#include "i_cast_session_manager_listener.h" +#include "i_cast_session_impl.h" +#include "i_cast_service_listener_impl.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace CastEngine { +class ICastSessionManagerService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.ICastSessionManagerService"); + + ICastSessionManagerService() = default; + ICastSessionManagerService(const ICastSessionManagerService &) = delete; + ICastSessionManagerService &operator=(const ICastSessionManagerService &) = delete; + ICastSessionManagerService(ICastSessionManagerService &&) = delete; + ICastSessionManagerService &operator=(ICastSessionManagerService &&) = delete; + ~ICastSessionManagerService() override = default; + + virtual int32_t RegisterListener(sptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t Release() = 0; + virtual int32_t SetLocalDevice(const CastLocalDevice &localDevice) = 0; + virtual int32_t CreateCastSession(const CastSessionProperty &property, sptr &castSession) = 0; + virtual int32_t SetSinkSessionCapacity(int sessionCapacity) = 0; + virtual int32_t StartDiscovery(int protocols) = 0; + virtual int32_t SetDiscoverable(bool enable) = 0; + virtual int32_t StopDiscovery() = 0; + virtual int32_t GetCastSession(std::string sessionId, sptr &castSession) = 0; + +protected: + enum { + REGISTER_LISTENER = 0, + UNREGISTER_LISTENER, + RELEASE, + SET_LOCAL_DEVICE, + CREATE_CAST_SESSION, + SET_SINK_SESSION_CAPACITY, + START_DISCOVERY, + SET_DISCOVERABLE, + STOP_DISCOVERY, + GET_CAST_SESSION + }; +}; +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/common/include/private/i_mirror_player_impl.h b/common/include/private/i_mirror_player_impl.h new file mode 100644 index 0000000..47da101 --- /dev/null +++ b/common/include/private/i_mirror_player_impl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast mirror player interface. + * Author: zhangjingnan + * Create: 2023-05-27 + */ + +#ifndef I_CAST_MIRROR_PLAYER_IMPL_H +#define I_CAST_MIRROR_PLAYER_IMPL_H + +#include + +#include "iremote_broker.h" +#include "oh_remote_control_event.h" +#include "surface_utils.h" + +namespace OHOS { +namespace CastEngine { +class IMirrorPlayerImpl : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.IMirrorPlayerImpl"); + + IMirrorPlayerImpl() = default; + IMirrorPlayerImpl(const IMirrorPlayerImpl &) = delete; + IMirrorPlayerImpl &operator=(const IMirrorPlayerImpl &) = delete; + IMirrorPlayerImpl(IMirrorPlayerImpl &&) = delete; + IMirrorPlayerImpl &operator=(IMirrorPlayerImpl &&) = delete; + ~IMirrorPlayerImpl() override = default; + + virtual int32_t Play(const std::string &deviceId) = 0; + virtual int32_t Pause(const std::string &deviceId) = 0; + virtual int32_t SetSurface(sptr producer) = 0; + virtual int32_t DeliverInputEvent(const OHRemoteControlEvent &event) = 0; + virtual int32_t Release() = 0; + +protected: + enum { + PLAY = 1, + PAUSE, + SET_SURFACE, + DELIVER_INPUT_EVENT, + RELEASE + }; +}; +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/common/include/private/i_stream_player_impl.h b/common/include/private/i_stream_player_impl.h new file mode 100644 index 0000000..dd363ad --- /dev/null +++ b/common/include/private/i_stream_player_impl.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player implement interface. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#ifndef I_STREAM_PLAYER_IMPL_H +#define I_STREAM_PLAYER_IMPL_H + +#include +#include "surface_utils.h" +#include "cast_engine_common.h" +#include "cast_service_common.h" +#include "i_stream_player_listener_impl.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace CastEngine { +class IStreamPlayerImpl : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.IStreamPlayerImpl"); + + IStreamPlayerImpl() = default; + IStreamPlayerImpl(const IStreamPlayerImpl &) = delete; + IStreamPlayerImpl &operator=(const IStreamPlayerImpl &) = delete; + IStreamPlayerImpl(IStreamPlayerImpl &&) = delete; + IStreamPlayerImpl &operator=(IStreamPlayerImpl &&) = delete; + virtual ~IStreamPlayerImpl() override = default; + + virtual int32_t RegisterListener(sptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t SetSurface(sptr producer) = 0; + virtual int32_t Load(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(int index) = 0; + virtual int32_t Play() = 0; + virtual int32_t Pause() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Next() = 0; + virtual int32_t Previous() = 0; + virtual int32_t Seek(int position) = 0; + virtual int32_t SetVolume(int volume) = 0; + virtual int32_t SetLoopMode(const LoopMode mode) = 0; + virtual int32_t SetSpeed(const PlaybackSpeed speed) = 0; + virtual int32_t GetPlayerStatus(PlayerStates &playerStates) = 0; + virtual int32_t GetPosition(int &position) = 0; + virtual int32_t GetDuration(int &duration) = 0; + virtual int32_t GetVolume(int &volume, int &maxVolume) = 0; + virtual int32_t GetLoopMode(LoopMode &loopMode) = 0; + virtual int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) = 0; + virtual int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) = 0; + virtual int32_t Release() = 0; + +protected: + enum { + REGISTER_LISTENER = 1, + UNREGISTER_LISTENER, + SET_SURFACE, + PLAY_INDEX, + LOAD, + START, + PAUSE, + PLAY, + STOP, + NEXT, + PREVIOUS, + SEEK, + SET_VOLUME, + SET_LOOP_MODE, + SET_SPEED, + GET_PLAYER_STATUS, + GET_POSITION, + GET_DURATION, + GET_VOLUME, + GET_LOOP_MODE, + GET_PLAY_SPEED, + GET_MEDIA_INFO_HOLDER, + RELEASE + }; + static const size_t MAX_PLAY_LIST_SIZE = 100; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/i_stream_player_ipc.h b/common/include/private/i_stream_player_ipc.h new file mode 100644 index 0000000..2ea18da --- /dev/null +++ b/common/include/private/i_stream_player_ipc.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player implement ipc interface. + * Author: zhangjingnan + * Create: 2023-08-29 + */ + +#ifndef I_STREAM_PLAYER_IPC_H +#define I_STREAM_PLAYER_IPC_H + +#include +#include "surface_utils.h" +#include "cast_engine_common.h" +#include "cast_service_common.h" +#include "i_stream_player_listener_impl.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace CastEngine { +class IStreamPlayerIpc : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.IStreamPlayerIpc"); + + IStreamPlayerIpc() = default; + IStreamPlayerIpc(const IStreamPlayerIpc &) = delete; + IStreamPlayerIpc &operator=(const IStreamPlayerIpc &) = delete; + IStreamPlayerIpc(IStreamPlayerIpc &&) = delete; + IStreamPlayerIpc &operator=(IStreamPlayerIpc &&) = delete; + virtual ~IStreamPlayerIpc() override = default; + + virtual int32_t RegisterListener(sptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t SetSurface(sptr producer) = 0; + virtual int32_t Load(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(int index) = 0; + virtual int32_t Play() = 0; + virtual int32_t Pause() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Next() = 0; + virtual int32_t Previous() = 0; + virtual int32_t Seek(int position) = 0; + virtual int32_t FastForward(int delta) = 0; + virtual int32_t FastRewind(int delta) = 0; + virtual int32_t SetVolume(int volume) = 0; + virtual int32_t SetLoopMode(const LoopMode mode) = 0; + virtual int32_t SetSpeed(const PlaybackSpeed speed) = 0; + virtual int32_t GetPlayerStatus(PlayerStates &playerStates) = 0; + virtual int32_t GetPosition(int &position) = 0; + virtual int32_t GetDuration(int &duration) = 0; + virtual int32_t GetVolume(int &volume, int &maxVolume) = 0; + virtual int32_t GetLoopMode(LoopMode &loopMode) = 0; + virtual int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) = 0; + virtual int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) = 0; + virtual int32_t Release() = 0; + +protected: + enum { + REGISTER_LISTENER = 1, + UNREGISTER_LISTENER, + SET_SURFACE, + PLAY_INDEX, + LOAD, + START, + PAUSE, + PLAY, + STOP, + NEXT, + PREVIOUS, + SEEK, + FAST_FORWARD, + FAST_REWIND, + SET_VOLUME, + SET_LOOP_MODE, + SET_SPEED, + GET_PLAYER_STATUS, + GET_POSITION, + GET_DURATION, + GET_VOLUME, + GET_LOOP_MODE, + GET_PLAY_SPEED, + GET_MEDIA_INFO_HOLDER, + RELEASE + }; + static const size_t MAX_PLAY_LIST_SIZE = 100; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/common/include/private/i_stream_player_listener_impl.h b/common/include/private/i_stream_player_listener_impl.h new file mode 100644 index 0000000..f10f840 --- /dev/null +++ b/common/include/private/i_stream_player_listener_impl.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Stream player listener implement interface. + * Author: huangchanggui + * Create: 2023-01-12 + */ + +#ifndef I_STREAM_PLAYER_LISTENER_IMPL_H +#define I_STREAM_PLAYER_LISTENER_IMPL_H + +#include "cast_engine_common.h" +#include "iremote_broker.h" + +namespace OHOS { +namespace CastEngine { +class IStreamPlayerListenerImpl : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.CastEngine.IStreamPlayerListenerImpl"); + IStreamPlayerListenerImpl() = default; + IStreamPlayerListenerImpl(const IStreamPlayerListenerImpl &) = delete; + IStreamPlayerListenerImpl &operator=(const IStreamPlayerListenerImpl &) = delete; + IStreamPlayerListenerImpl(IStreamPlayerListenerImpl &&) = delete; + IStreamPlayerListenerImpl &operator=(IStreamPlayerListenerImpl &&) = delete; + virtual ~IStreamPlayerListenerImpl() override = default; + + virtual void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) = 0; + virtual void OnPositionChanged(int position, int bufferPosition, int duration) = 0; + virtual void OnMediaItemChanged(const MediaInfo &mediaInfo) = 0; + virtual void OnVolumeChanged(int volume, int maxVolume) = 0; + virtual void OnPlayerError(int errorCode, const std::string &errorMsg) = 0; + virtual void OnVideoSizeChanged(int width, int height) = 0; + virtual void OnLoopModeChanged(const LoopMode loopMode) = 0; + virtual void OnPlaySpeedChanged(const PlaybackSpeed speed) = 0; + virtual void OnNextRequest() = 0; + virtual void OnPreviousRequest() = 0; + virtual void OnSeekDone(int position) = 0; + virtual void OnEndOfStream(int isLooping) = 0; + virtual void OnPlayRequest(const MediaInfo &mediaInfo) = 0; + +protected: + enum { + ON_PLAYER_STATUS_CHANGED = 1, + ON_POSITION_CHANGED, + ON_MEDIA_ITEM_CHANGED, + ON_VOLUME_CHANGED, + ON_REPEAT_MODE_CHANGED, + ON_PLAY_SPEED_CHANGED, + ON_PLAYER_ERROR, + ON_VIDEO_SIZE_CHANGED, + ON_NEXT_REQUEST, + ON_PREVIOUS_REQUEST, + ON_SEEK_DONE, + ON_END_OF_STREAM, + ON_PLAY_REQUEST + }; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/common/src/cast_engine_common_helper.cpp b/common/src/cast_engine_common_helper.cpp new file mode 100644 index 0000000..5fc14ac --- /dev/null +++ b/common/src/cast_engine_common_helper.cpp @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply a helper to write/read common cast engine structures through ipc + * Author: zhangge + * Create: 2022-06-15 + */ + +#include "cast_engine_common_helper.h" + +#include +#include "cast_engine_log.h" +#include "securec.h" + +namespace OHOS { +namespace CastEngine { +DEFINE_CAST_ENGINE_LABEL("Cast-Engine-helper"); + +namespace { +bool WriteVideoSize(Parcel &parcel, const VideoSize &videoSize) +{ + return parcel.WriteInt32(videoSize.width) && parcel.WriteInt32(videoSize.height); +} + +const VideoSize ReadVideoSize(Parcel &parcel) +{ + return { static_cast(parcel.ReadInt32()), static_cast(parcel.ReadInt32()) }; +} + +bool WriteWindowProperty(Parcel &parcel, const WindowProperty &property) +{ + return parcel.WriteInt32(property.startX) && parcel.WriteInt32(property.startY) && + parcel.WriteInt32(property.width) && parcel.WriteInt32(property.height); +} + +const WindowProperty ReadWindowProperty(Parcel &parcel) +{ + WindowProperty property; + property.startX = static_cast(parcel.ReadInt32()); + property.startY = static_cast(parcel.ReadInt32()); + property.width = static_cast(parcel.ReadInt32()); + property.height = static_cast(parcel.ReadInt32()); + + return property; +} + +bool WriteVideoProperty(Parcel &parcel, const VideoProperty &property) +{ + return parcel.WriteInt32(static_cast(property.videoWidth)) && + parcel.WriteInt32(static_cast(property.videoHeight)) && + parcel.WriteInt32(static_cast(property.fps)) && + parcel.WriteInt32(static_cast(property.codecType)) && + parcel.WriteInt32(static_cast(property.gop)) && + parcel.WriteInt32(static_cast(property.bitrate)) && + parcel.WriteInt32(static_cast(property.minBitrate)) && + parcel.WriteInt32(static_cast(property.maxBitrate)) && + parcel.WriteInt32(static_cast(property.dpi)) && + parcel.WriteInt32(static_cast(property.colorStandard)) && + parcel.WriteInt32(static_cast(property.screenWidth)) && + parcel.WriteInt32(static_cast(property.screenHeight)) && + parcel.WriteInt32(static_cast(property.profile)) && + parcel.WriteInt32(static_cast(property.level)); +} + +std::optional ReadVideoProperty(Parcel &parcel) +{ + VideoProperty property; + property.videoWidth = static_cast(parcel.ReadInt32()); + property.videoHeight = static_cast(parcel.ReadInt32()); + property.fps = static_cast(parcel.ReadInt32()); + auto codecType = parcel.ReadInt32(); + property.gop = static_cast(parcel.ReadInt32()); + property.bitrate = static_cast(parcel.ReadInt32()); + property.minBitrate = static_cast(parcel.ReadInt32()); + property.maxBitrate = static_cast(parcel.ReadInt32()); + property.dpi = static_cast(parcel.ReadInt32()); + auto colorStandard = parcel.ReadInt32(); + property.screenWidth = static_cast(parcel.ReadInt32()); + property.screenHeight = static_cast(parcel.ReadInt32()); + property.profile = static_cast(parcel.ReadInt32()); + property.level = static_cast(parcel.ReadInt32()); + + if (!IsColorStandard(colorStandard) || !IsVideoCodecType(codecType)) { + return std::nullopt; + } + + property.codecType = static_cast(codecType); + property.colorStandard = static_cast(colorStandard); + return property; +} + + +bool WriteAudioProperty(Parcel &parcel, const AudioProperty &property) +{ + return parcel.WriteInt32(static_cast(property.sampleRate)) && + parcel.WriteInt32(static_cast(property.sampleBitWidth)) && + parcel.WriteInt32(static_cast(property.channelConfig)) && + parcel.WriteInt32(static_cast(property.bitrate)) && + parcel.WriteInt32(static_cast(property.codec)); +} + +const AudioProperty ReadAudioProperty(Parcel &parcel) +{ + AudioProperty property; + property.sampleRate = static_cast(parcel.ReadInt32()); + property.sampleBitWidth = static_cast(parcel.ReadInt32()); + property.channelConfig = static_cast(parcel.ReadInt32()); + property.bitrate = static_cast(parcel.ReadInt32()); + property.codec = static_cast(parcel.ReadInt32()); + return property; +} + +int GetLocalFd(const std::string &url) +{ + char *nextPtr = nullptr; + int fd = static_cast(std::strtol(url.c_str(), &nextPtr, DECIMALISM)); + if (errno == ERANGE || *nextPtr != '\0') { + return INVALID_VALUE; + } + return fd; +} +} // namespace + +bool WriteCastRemoteDevice(Parcel &parcel, const CastRemoteDevice &device) +{ + return parcel.WriteInt32(static_cast(device.deviceType)) && + parcel.WriteInt32(static_cast(device.subDeviceType)) && + parcel.WriteInt32(static_cast(device.channelType)) && parcel.WriteString(device.deviceId) && + parcel.WriteString(device.deviceName) && parcel.WriteString(device.ipAddress); +} + +bool ReadCastRemoteDevice(Parcel &parcel, CastRemoteDevice &device) +{ + auto remote = ReadCastRemoteDevice(parcel); + if (remote == nullptr) { + CLOGE("ReadCastRemoteDevice failed"); + return false; + } + + device = *remote; + return true; +} + +std::unique_ptr ReadCastRemoteDevice(Parcel &parcel) +{ + auto device = std::make_unique(); + auto deviceType = parcel.ReadInt32(); + auto subDeviceType = parcel.ReadInt32(); + auto channelType = parcel.ReadInt32(); + device->deviceType = static_cast(deviceType); + device->subDeviceType = static_cast(subDeviceType); + device->channelType = static_cast(channelType); + device->deviceId = parcel.ReadString(); + device->deviceName = parcel.ReadString(); + device->ipAddress = parcel.ReadString(); + if (!IsDeviceType(deviceType) || !IsSubDeviceType(subDeviceType) || !IsChannelType(channelType)) { + CLOGE("ReadCastRemoteDevice error"); + return nullptr; + } + return device; +} + +bool WriteMediaInfo(MessageParcel &parcel, const MediaInfo &mediaInfo) +{ + if (mediaInfo.mediaUrl.empty()) { + CLOGE("mediaUrl is empty"); + return false; + } + int fd = GetLocalFd(mediaInfo.mediaUrl); + if (fd != INVALID_VALUE) { + if (!parcel.WriteString("localFd") || !parcel.WriteFileDescriptor(fd)) { + CLOGE("Write local fd failed, fd = %{public}d", fd); + return false; + } + } else if (!parcel.WriteString("path") || !parcel.WriteString(mediaInfo.mediaUrl)) { + CLOGE("Write path failed"); + return false; + } + return parcel.WriteString(mediaInfo.mediaId) && parcel.WriteString(mediaInfo.mediaName) && + parcel.WriteString(mediaInfo.mediaType) && parcel.WriteUint32(mediaInfo.mediaSize) && + parcel.WriteString(mediaInfo.albumCoverUrl) && parcel.WriteString(mediaInfo.albumTitle) && + parcel.WriteString(mediaInfo.mediaArtist) && parcel.WriteString(mediaInfo.lrcUrl) && + parcel.WriteString(mediaInfo.lrcContent) && parcel.WriteString(mediaInfo.appIconUrl) && + parcel.WriteString(mediaInfo.appName) && parcel.WriteUint32(mediaInfo.startPosition) && + parcel.WriteUint32(mediaInfo.duration) && parcel.WriteUint32(mediaInfo.closingCreditsPosition); +} + +std::unique_ptr ReadMediaInfo(MessageParcel &parcel) +{ + auto mediaInfo = std::make_unique(); + if (mediaInfo == nullptr) { + CLOGE("Failed to malloc mediaInfo"); + return nullptr; + } + std::string urlType = parcel.ReadString(); + if (urlType == "localFd") { + CLOGD("localFd"); + mediaInfo->mediaUrl = std::to_string(parcel.ReadFileDescriptor()); + } else { + CLOGD("online or localPath"); + mediaInfo->mediaUrl = parcel.ReadString(); + } + mediaInfo->mediaId = parcel.ReadString(); + mediaInfo->mediaName = parcel.ReadString(); + mediaInfo->mediaType = parcel.ReadString(); + mediaInfo->mediaSize = parcel.ReadUint32(); + mediaInfo->albumCoverUrl = parcel.ReadString(); + mediaInfo->albumTitle = parcel.ReadString(); + mediaInfo->mediaArtist = parcel.ReadString(); + mediaInfo->lrcUrl = parcel.ReadString(); + mediaInfo->lrcContent = parcel.ReadString(); + mediaInfo->appIconUrl = parcel.ReadString(); + mediaInfo->appName = parcel.ReadString(); + mediaInfo->startPosition = parcel.ReadUint32(); + mediaInfo->duration = parcel.ReadUint32(); + mediaInfo->closingCreditsPosition = parcel.ReadUint32(); + + return mediaInfo; +} + +bool WriteMediaInfoHolder(MessageParcel &parcel, const MediaInfoHolder &mediaInfoHolder) +{ + bool ret = parcel.WriteUint32(mediaInfoHolder.currentIndex); + ret = ret && parcel.WriteUint32(mediaInfoHolder.progressRefreshInterval); + ret = ret && parcel.WriteUint32(static_cast(mediaInfoHolder.mediaInfoList.size())); + for (auto iter = mediaInfoHolder.mediaInfoList.begin(); iter != mediaInfoHolder.mediaInfoList.end(); iter++) { + ret = ret && WriteMediaInfo(parcel, *iter); + } + return ret; +} + +std::unique_ptr ReadMediaInfoHolder(MessageParcel &parcel) +{ + auto mediaInfoHolder = std::make_unique(); + if (mediaInfoHolder == nullptr) { + CLOGE("Failed to malloc mediaInfoHolder"); + return nullptr; + } + mediaInfoHolder->currentIndex = parcel.ReadUint32(); + mediaInfoHolder->progressRefreshInterval = parcel.ReadUint32(); + uint32_t infoListSize = parcel.ReadUint32(); + if (infoListSize > MAX_FILE_NUM) { + CLOGE("The number of list exceeds the upper limit. infoListSize: %{public}u", infoListSize); + return nullptr; + } + for (uint32_t i = 0; i < infoListSize; i++) { + auto mediaInfo = ReadMediaInfo(parcel); + if (mediaInfo == nullptr) { + return nullptr; + } + mediaInfoHolder->mediaInfoList.push_back(*mediaInfo); + } + return mediaInfoHolder; +} + +bool WriteCastLocalDevice(Parcel &parcel, const CastLocalDevice &device) +{ + return parcel.WriteString(device.deviceId) && parcel.WriteString(device.deviceName) && + parcel.WriteInt32(static_cast(device.deviceType)) && + parcel.WriteInt32(static_cast(device.subDeviceType)) && parcel.WriteString(device.ipAddress) && + parcel.WriteInt32(static_cast(device.triggerType)) && parcel.WriteString(device.authData); +} + +std::unique_ptr ReadCastLocalDevice(Parcel &parcel) +{ + auto device = std::make_unique(); + device->deviceId = parcel.ReadString(); + device->deviceName = parcel.ReadString(); + auto deviceType = parcel.ReadInt32(); + auto subDeviceType = parcel.ReadInt32(); + device->ipAddress = parcel.ReadString(); + auto triggerType = parcel.ReadInt32(); + device->authData = parcel.ReadString(); + + if (!IsDeviceType(deviceType) || !IsSubDeviceType(subDeviceType) || !IsTriggerType(triggerType)) { + CLOGE("ReadCastLocalDevice error"); + return nullptr; + } + device->deviceType = static_cast(deviceType); + device->subDeviceType = static_cast(subDeviceType); + device->triggerType = static_cast(triggerType); + + return device; +} + +bool WriteCastSessionProperty(Parcel &parcel, const CastSessionProperty &property) +{ + return parcel.WriteInt32(static_cast(property.protocolType)) && + parcel.WriteInt32(static_cast(property.endType)) && + WriteAudioProperty(parcel, property.audioProperty) && WriteVideoProperty(parcel, property.videoProperty) && + WriteWindowProperty(parcel, property.windowProperty); +} + +std::unique_ptr ReadCastSessionProperty(Parcel &parcel) +{ + auto property = std::make_unique(); + if (property == nullptr) { + CLOGE("Failed to malloc cast session property"); + return nullptr; + } + auto protocolType = parcel.ReadInt32(); + if (!IsProtocolType(protocolType)) { + return nullptr; + } + auto endType = parcel.ReadInt32(); + if (!IsEndType(endType)) { + return nullptr; + } + + property->protocolType = static_cast(protocolType); + property->endType = static_cast(endType); + property->audioProperty = ReadAudioProperty(parcel); + auto videoProperty = ReadVideoProperty(parcel); + if (videoProperty == std::nullopt) { + return nullptr; + } + property->videoProperty = videoProperty.value(); + property->windowProperty = ReadWindowProperty(parcel); + return property; +} + +bool WritePropertyContainer(Parcel &parcel, const PropertyContainer &container) +{ + return parcel.WriteInt32(static_cast(container.type)) && + (((container.type == PropertyType::VIDEO_SIZE) && WriteVideoSize(parcel, container.videoSize)) || + ((container.type == PropertyType::VIDEO_FPS) && parcel.WriteInt32(container.videoFps)) || + ((container.type == PropertyType::WINDOW_SIZE) && WriteWindowProperty(parcel, container.windowProperty))); +} + +std::unique_ptr ReadPropertyContainer(Parcel &parcel) +{ + auto container = std::make_unique(); + if (container == nullptr) { + CLOGE("Failed to malloc property container"); + return nullptr; + } + int32_t type = parcel.ReadInt32(); + if (!IsPropertyType(type)) { + return nullptr; + } + container->type = static_cast(type); + if (container->type == PropertyType::VIDEO_SIZE) { + container->videoSize = ReadVideoSize(parcel); + } else if (container->type == PropertyType::VIDEO_FPS) { + container->videoFps = static_cast(parcel.ReadInt32()); + } else { + container->windowProperty = ReadWindowProperty(parcel); + } + + return container; +} + +bool WriteAuthInfo(Parcel &parcel, const AuthInfo &authInfo) +{ + return parcel.WriteInt32(static_cast(authInfo.authMode)) && + parcel.WriteInt32(static_cast(authInfo.authCode)) && parcel.WriteString(authInfo.deviceId); +} + +std::unique_ptr ReadAuthInfo(Parcel &parcel) +{ + auto authInfo = std::make_unique(); + if (authInfo == nullptr) { + CLOGE("Failed to malloc auth info"); + return nullptr; + } + + authInfo->authMode = static_cast(parcel.ReadInt32()); + authInfo->authCode = static_cast(parcel.ReadInt32()); + authInfo->deviceId = parcel.ReadString(); + return authInfo; +} + +bool WriteTouchPoint(Parcel &parcel, const OHNativeXcomponentTouchPoint &touchPoint) +{ + return parcel.WriteInt32(touchPoint.id) && parcel.WriteFloat(touchPoint.screenX) && + parcel.WriteFloat(touchPoint.screenY) && parcel.WriteFloat(touchPoint.x) && parcel.WriteFloat(touchPoint.y) && + parcel.WriteUint32(static_cast(touchPoint.type)) && parcel.WriteDouble(touchPoint.size) && + parcel.WriteFloat(touchPoint.force) && parcel.WriteInt64(touchPoint.timeStamp) && + parcel.WriteBool(touchPoint.isPressed); +} + +bool WriteTouchPoints(Parcel &parcel, const OHNativeXcomponentTouchEvent touchEvent) +{ + for (uint32_t i = 0; i < touchEvent.numPoints; i++) { + if (!WriteTouchPoint(parcel, touchEvent.touchPoints[i])) { + return false; + } + } + return true; +} + +bool WriteTouchEvent(Parcel &parcel, const OHNativeXcomponentTouchEvent &touchEvent) +{ + return parcel.WriteInt32(touchEvent.id) && parcel.WriteFloat(touchEvent.screenX) && + parcel.WriteFloat(touchEvent.screenY) && parcel.WriteFloat(touchEvent.x) && parcel.WriteFloat(touchEvent.y) && + parcel.WriteUint32(static_cast(touchEvent.type)) && parcel.WriteDouble(touchEvent.size) && + parcel.WriteFloat(touchEvent.force) && parcel.WriteInt64(touchEvent.deviceId) && + parcel.WriteInt64(touchEvent.timeStamp) && parcel.WriteUint32(touchEvent.numPoints) && + WriteTouchPoints(parcel, touchEvent); +} + + +bool WriteMouseEvent(Parcel &parcel, const OHNativeXcomponentMouseEvent &mouseEvent) +{ + return parcel.WriteFloat(mouseEvent.x) && parcel.WriteFloat(mouseEvent.y) && + parcel.WriteFloat(mouseEvent.screenX) && parcel.WriteFloat(mouseEvent.screenY) && + parcel.WriteInt64(mouseEvent.timestamp) && parcel.WriteUint32(static_cast(mouseEvent.action)) && + parcel.WriteUint32(static_cast(mouseEvent.button)); +} + +bool WriteWhellEvent(Parcel &parcel, const OHNativeXcomponentWheelEvent &wheelEvent) +{ + return parcel.WriteUint32(static_cast(wheelEvent.direction)) && + parcel.WriteUint8(wheelEvent.indication) && parcel.WriteUint8(wheelEvent.scrollUnit) && + parcel.WriteUint16(wheelEvent.wheelDis) && parcel.WriteFloat(wheelEvent.x) && parcel.WriteFloat(wheelEvent.y); +} + +bool WriteKeyEvent(Parcel &parcel, const OHNativeXcomponentKeyEvent &keyEvent) +{ + return parcel.WriteUint8(keyEvent.reserved) && parcel.WriteUint16(keyEvent.keyCode1) && + parcel.WriteUint16(keyEvent.keyCode2) && parcel.WriteUint32(keyEvent.metaState) && + parcel.WriteUint32(static_cast(keyEvent.type)); +} + +bool WriteContentEvent(Parcel &parcel, const OHNativeXcomponentContentEvent &contentEvent) +{ + return parcel.WriteUint16(contentEvent.msgLen) && parcel.WriteCString(contentEvent.inputText); +} + +bool WriteFocusEvent(Parcel &parcel, const OHNativeXcomponentFocusEvent &focusEvent) +{ + return parcel.WriteUint8(focusEvent.focusStat) && parcel.WriteDouble(focusEvent.cursorX1) && + parcel.WriteDouble(focusEvent.cursorY1) && parcel.WriteDouble(focusEvent.cursorX2) && + parcel.WriteDouble(focusEvent.cursorY2); +} + +bool WriteInputMethodEvent(Parcel &parcel, const OHNativeXcomponentInputMethodEvent &inputMethodEvent) +{ + return parcel.WriteUint32(static_cast(inputMethodEvent.type)) && + (((inputMethodEvent.type == OHNativeXcomponentInputMethodEventType::OH_NATIVEXCOMPONENT_INPUT_CONTENT) && + WriteContentEvent(parcel, inputMethodEvent.contentEvent)) || + ((inputMethodEvent.type == OHNativeXcomponentInputMethodEventType::OH_NATIVEXCOMPONENT_INPUT_FOCUS) && + WriteFocusEvent(parcel, inputMethodEvent.focusEvent))); +} + +bool WriteVirtualKeyEvent(Parcel &parcel, const OHNativeXcomponentVirtualKeyEvent &virtualKeyEvent) +{ + return parcel.WriteInt32(static_cast(virtualKeyEvent.type)) && parcel.WriteFloat(virtualKeyEvent.x) && + parcel.WriteFloat(virtualKeyEvent.y); +} + +bool WriteRemoteControlEvent(Parcel &parcel, const OHRemoteControlEvent &event) +{ + return parcel.WriteInt32(static_cast(event.eventType)) && + (((event.eventType == XcomponentEventType::REMOTECONTROL_TOUCH) && WriteTouchEvent(parcel, event.touchEvent)) || + ((event.eventType == XcomponentEventType::REMOTECONTROL_MOUSE) && WriteMouseEvent(parcel, event.mouseEvent)) || + ((event.eventType == XcomponentEventType::REMOTECONTROL_WHEEL) && WriteWhellEvent(parcel, event.wheelEvent)) || + ((event.eventType == XcomponentEventType::REMOTECONTROL_KEY) && WriteKeyEvent(parcel, event.keyEvent)) || + ((event.eventType == XcomponentEventType::REMOTECONTROL_INPUT_METHOD) && + WriteInputMethodEvent(parcel, event.inputMethodEvent)) || + ((event.eventType == XcomponentEventType::REMOTECONTROL_VIRTUAL_KEY) && + WriteVirtualKeyEvent(parcel, event.virtualKeyEvent))); +} + +const OHNativeXcomponentTouchPoint ReadTouchPoint(Parcel &parcel) +{ + return { parcel.ReadInt32(), parcel.ReadFloat(), + parcel.ReadFloat(), parcel.ReadFloat(), + parcel.ReadFloat(), static_cast(parcel.ReadUint32()), + parcel.ReadDouble(), parcel.ReadFloat(), + parcel.ReadInt64(), parcel.ReadBool() }; +} + +void ReadTouchPoints(Parcel &parcel, uint32_t numPoints, OHNativeXcomponentTouchPoint points[]) +{ + for (uint32_t i = 0; i < numPoints; i++) { + points[i] = ReadTouchPoint(parcel); + } +} + +void ReadTouchEvent(Parcel &parcel, OHNativeXcomponentTouchEvent &touchEvent) +{ + touchEvent.id = parcel.ReadInt32(); + touchEvent.screenX = parcel.ReadFloat(); + touchEvent.screenY = parcel.ReadFloat(); + touchEvent.x = parcel.ReadFloat(); + touchEvent.y = parcel.ReadFloat(); + touchEvent.type = static_cast(parcel.ReadUint32()); + touchEvent.size = parcel.ReadDouble(); + touchEvent.force = parcel.ReadFloat(); + touchEvent.deviceId = parcel.ReadInt64(); + touchEvent.timeStamp = parcel.ReadInt64(); + touchEvent.numPoints = parcel.ReadUint32(); + ReadTouchPoints(parcel, touchEvent.numPoints, touchEvent.touchPoints); +} + +const OHNativeXcomponentMouseEvent ReadMouseEvent(Parcel &parcel) +{ + return { parcel.ReadFloat(), + parcel.ReadFloat(), + parcel.ReadFloat(), + parcel.ReadFloat(), + parcel.ReadInt64(), + static_cast(parcel.ReadUint32()), + static_cast(parcel.ReadUint32()) }; +} + +const OHNativeXcomponentWheelEvent ReadWhellEvent(Parcel &parcel) +{ + return { static_cast(parcel.ReadUint32()), + parcel.ReadUint8(), + parcel.ReadUint8(), + parcel.ReadUint16(), + parcel.ReadFloat(), + parcel.ReadFloat() }; +} + +const OHNativeXcomponentKeyEvent ReadKeyEvent(Parcel &parcel) +{ + return { parcel.ReadUint8(), parcel.ReadUint16(), parcel.ReadUint16(), parcel.ReadUint32(), + static_cast(parcel.ReadUint32()) }; +} + +void ReadContentEvent(Parcel &parcel, OHNativeXcomponentContentEvent &contentEvent) +{ + contentEvent.msgLen = parcel.ReadUint16(); + if (strcpy_s(contentEvent.inputText, OH_MAX_CONTENT_LEN, parcel.ReadCString()) != EOK) { + CLOGE("Failed copy content to array"); + } +} + +const OHNativeXcomponentFocusEvent ReadFocusEvent(Parcel &parcel) +{ + return { parcel.ReadUint8(), parcel.ReadDouble(), parcel.ReadDouble(), parcel.ReadDouble(), parcel.ReadDouble() }; +} + + +void ReadInputMethodEvent(Parcel &parcel, OHNativeXcomponentInputMethodEvent &inputMethodEvent) +{ + inputMethodEvent.type = static_cast(parcel.ReadUint16()); + if (inputMethodEvent.type == OHNativeXcomponentInputMethodEventType::OH_NATIVEXCOMPONENT_INPUT_CONTENT) { + return ReadContentEvent(parcel, inputMethodEvent.contentEvent); + } + inputMethodEvent.focusEvent = ReadFocusEvent(parcel); +} + +const OHNativeXcomponentVirtualKeyEvent ReadVirtualKeyEvent(Parcel &parcel) +{ + return { static_cast(parcel.ReadInt32()), parcel.ReadFloat(), + parcel.ReadFloat() }; +} + +std::unique_ptr ReadRemoteControlEvent(Parcel &parcel) +{ + auto remoteControlEvent = std::make_unique(); + if (remoteControlEvent == nullptr) { + CLOGE("Failed to malloc remote control event"); + return nullptr; + } + + remoteControlEvent->eventType = static_cast(parcel.ReadUint32()); + switch (remoteControlEvent->eventType) { + case XcomponentEventType::REMOTECONTROL_TOUCH: + ReadTouchEvent(parcel, remoteControlEvent->touchEvent); + break; + case XcomponentEventType::REMOTECONTROL_MOUSE: + remoteControlEvent->mouseEvent = ReadMouseEvent(parcel); + break; + case XcomponentEventType::REMOTECONTROL_WHEEL: + remoteControlEvent->wheelEvent = ReadWhellEvent(parcel); + break; + case XcomponentEventType::REMOTECONTROL_KEY: + remoteControlEvent->keyEvent = ReadKeyEvent(parcel); + break; + case XcomponentEventType::REMOTECONTROL_INPUT_METHOD: + ReadInputMethodEvent(parcel, remoteControlEvent->inputMethodEvent); + break; + case XcomponentEventType::REMOTECONTROL_VIRTUAL_KEY: + remoteControlEvent->virtualKeyEvent = ReadVirtualKeyEvent(parcel); + break; + default: + CLOGE("Parameter error, event:(%d) not support", static_cast(remoteControlEvent->eventType)); + remoteControlEvent = nullptr; + break; + } + return remoteControlEvent; +} + +bool WriteDeviceStateInfo(Parcel &parcel, const DeviceStateInfo &stateInfo) +{ + return parcel.WriteInt32(static_cast(stateInfo.deviceState)) && parcel.WriteString(stateInfo.deviceId); +} + +std::unique_ptr ReadDeviceStateInfo(Parcel &parcel) +{ + auto stateInfo = std::make_unique(); + int32_t state = parcel.ReadInt32(); + if (!IsDeviceState(state)) { + CLOGE("incorrect device state"); + return nullptr; + } + stateInfo->deviceState = static_cast(state); + stateInfo->deviceId = parcel.ReadString(); + if (stateInfo->deviceId.empty()) { + CLOGE("device id is empty"); + return nullptr; + } + + return stateInfo; +} + +bool WriteEvent(Parcel &parcel, const EventId &eventId, const std::string &jsonParam) +{ + return parcel.WriteInt32(static_cast(eventId)) && parcel.WriteString(jsonParam); +} + +bool ReadEvent(Parcel &parcel, int32_t &eventId, std::string &jsonParam) +{ + eventId = parcel.ReadInt32(); + if (!IsEventId(eventId)) { + CLOGE("incorrect event id"); + return false; + } + jsonParam = parcel.ReadString(); + return true; +} + +void SetDataCapacity(MessageParcel &parcel, const FileFdMap &fileList, uint32_t tokenSize) +{ + uint32_t totalSize = tokenSize; + totalSize += sizeof(uint32_t); + for (const auto &[srcPath, fdPair] : fileList) { + totalSize += srcPath.length(); + totalSize += sizeof(fdPair.first); + totalSize += fdPair.second.length(); + } + if (totalSize > parcel.GetDataCapacity()) { + CLOGD("SetDataCapacity totalSize: %d", totalSize); + parcel.SetMaxCapacity(totalSize + totalSize); + parcel.SetDataCapacity(totalSize); + } +} + +bool WriteFileList(MessageParcel &parcel, const FileFdMap &fileList) +{ + bool ret = parcel.WriteUint32(fileList.size()); + for (const auto &[srcPath, fdPair] : fileList) { + ret = ret && parcel.WriteString(srcPath); + ret = ret && parcel.WriteFileDescriptor(fdPair.first); + ret = ret && parcel.WriteString(fdPair.second); + } + return ret; +} + +bool ReadFileList(MessageParcel &parcel, FileFdMap &fileList) +{ + uint32_t fileListSize = parcel.ReadUint32(); + if (fileListSize > MAX_FILE_NUM) { + CLOGE("The number of files exceeds the upper limit. fileListSize: %{public}u", fileListSize); + return false; + } + for (uint32_t i = 0; i < fileListSize; i++) { + std::string src = parcel.ReadString(); + int32_t fd = parcel.ReadFileDescriptor(); + std::string dst = parcel.ReadString(); + fileList[src] = std::make_pair(fd, dst); + } + return true; +} + +bool WriteRcvFdFileMap(MessageParcel &parcel, const RcvFdFileMap &rcvFdFileMap) +{ + bool ret = parcel.WriteUint32(rcvFdFileMap.size()); + for (const auto &[fd, path] : rcvFdFileMap) { + ret = ret && parcel.WriteFileDescriptor(fd); + ret = ret && parcel.WriteString(path); + } + return ret; +} + +bool ReadRcvFdFileMap(MessageParcel &parcel, RcvFdFileMap &rcvFdFileMap) +{ + uint32_t fileListSize = parcel.ReadUint32(); + if (fileListSize > MAX_FILE_NUM) { + CLOGE("The number of files exceeds the upper limit. fileListSize: %{public}u", fileListSize); + return false; + } + for (uint32_t i = 0; i < fileListSize; i++) { + int32_t fd = parcel.ReadFileDescriptor(); + std::string path = parcel.ReadString(); + rcvFdFileMap[fd] = path; + } + return true; +} +} // namespace CastEngine +} // namespace OHOS diff --git a/common/src/cast_engine_dfx.cpp b/common/src/cast_engine_dfx.cpp new file mode 100644 index 0000000..7ef922c --- /dev/null +++ b/common/src/cast_engine_dfx.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast engine dfx. + * Author: wangxueshuang + * Create: 2023-06-05 + */ + +#include "cast_engine_dfx.h" + +#include + +#include "cast_engine_log.h" +#include "hisysevent.h" +#include "json.hpp" + +using nlohmann::json; + +namespace OHOS { +namespace CastEngine { +DEFINE_CAST_ENGINE_LABEL("Cast-Dfx"); + +json CastEngineDfx::jsonSteamInfo_ = {}; +json CastEngineDfx::jsonLocalDeviceInfo_ = {}; +json CastEngineDfx::jsonRemoteDeviceInfo_ = {}; +json CastEngineDfx::jsonConnectInfo_ = {}; +const std::string CastEngineDfx::PACKAGE_NAME = "CastEngineService"; +const std::string CastEngineDfx::SEQUENTIAL_ID_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +void CastEngineDfx::WriteErrorEvent(int32_t errorCode) +{ + CLOGD("In."); + HiSysEventWrite(CAST_ENGINE_DFX_DOMAIN_NAME, "CAST_ENGINE_ERR", HiviewDFX::HiSysEvent::EventType::FAULT, + "ERROR_CODE", errorCode); +} + +void CastEngineDfx::SetStreamInfo(const std::string &streamInfoKey, const std::string &streamInfoValue) +{ + CLOGD("In."); + jsonSteamInfo_[streamInfoKey] = streamInfoValue; +} + +std::string CastEngineDfx::GetStreamInfo() +{ + CLOGD("In."); + return jsonSteamInfo_.dump(); +} + +void CastEngineDfx::SetLocalDeviceInfo(const std::string &localDeviceInfoKey, const std::string &localDeviceInfoValue) +{ + CLOGD("In."); + jsonLocalDeviceInfo_[localDeviceInfoKey] = localDeviceInfoValue; +} + +std::string CastEngineDfx::GetLocalDeviceInfo() +{ + CLOGD("In."); + return jsonLocalDeviceInfo_.dump(); +} + +void CastEngineDfx::SetRemoteDeviceInfo(const std::string &remoteDeviceInfoKey, + const std::string &remoteDeviceInfoValue) +{ + CLOGD("In."); + jsonRemoteDeviceInfo_[remoteDeviceInfoKey] = remoteDeviceInfoValue; +} + +std::string CastEngineDfx::GetRemoteDeviceInfo() +{ + CLOGD("In."); + return jsonRemoteDeviceInfo_.dump(); +} + +void CastEngineDfx::SetConnectInfo(const std::string &connectInfoKey, const std::string &connectInfoValue) +{ + CLOGD("In."); + jsonConnectInfo_[connectInfoKey] = connectInfoValue; +} + +std::string CastEngineDfx::GetConnectInfo() +{ + CLOGD("In."); + return jsonConnectInfo_.dump(); +} + +std::string CastEngineDfx::GetSequentialId() +{ + CLOGD("In."); + std::string sequentialId = ""; + srand(static_cast(time(NULL))); + for (int i = 0; i < SN_LENGTH; i++) { + int number = rand() % SEQUENTIAL_ID_CHARS_LENGTH; + sequentialId.push_back(SEQUENTIAL_ID_CHARS[number]); + } + CLOGD("sequential ID: %s.", sequentialId.c_str()); + return sequentialId; +} + +std::string CastEngineDfx::GetBizPackageName() +{ + CLOGD("In."); + return PACKAGE_NAME; +} +} // namespace CastEngine +} // namespace OHOS diff --git a/etc/init/BUILD.gn b/etc/init/BUILD.gn new file mode 100644 index 0000000..4a22935 --- /dev/null +++ b/etc/init/BUILD.gn @@ -0,0 +1,16 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//build/ohos.gni") + +ohos_prebuilt_etc("cast_engine_service.cfg") { + source = "cast_engine_service.cfg" + relative_install_dir = "init" + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/etc/init/cast_engine_service.cfg b/etc/init/cast_engine_service.cfg new file mode 100644 index 0000000..79e3eae --- /dev/null +++ b/etc/init/cast_engine_service.cfg @@ -0,0 +1,25 @@ +{ + "jobs" : [{ + "name" : "post-fs-data", + "cmds" : [ + "mkdir /data/service/el1/public/cast_engine_service 0700 cast_engine_service cast_engine_service" + ] + } + ], + "services" : [{ + "name" : "cast_engine_service", + "path" : ["/system/bin/sa_main", "/system/profile/cast_engine_service.json"], + "ondemand" : true, + "uid" : "cast_engine_service", + "gid" : ["cast_engine_service", "shell"], + "permission" : [ + "ohos.permission.DISTRIBUTED_DATASYNC", + "ohos.permission.CAPTURE_SCREEN", + "ohos.permission.ACCESS_SERVICE_DM", + "ohos.permission.MICROPHONE" + ], + "permission_acls" : ["ohos.permission.CAPTURE_SCREEN"], + "secon" : "u:r:cast_engine_service:s0" + } + ] +} diff --git a/hisysevent.yaml b/hisysevent.yaml new file mode 100644 index 0000000..57512ee --- /dev/null +++ b/hisysevent.yaml @@ -0,0 +1,64 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Description: hisysevent +# Author: wangxueshuang +# Create: 2023-01-30 + +domain: CAST_ENGINE + +CAST_ENGINE_ERR: + __BASE: {type: FAULT, level: CRITICAL, desc: projection error events} + SEQUENTIAL_ID: {type: STRING, desc: used to associate projection events} + CAST_SESSION_ID: {type: INT32, desc: projection session ID} + ERROR_CODE: {type: INT32, desc: error code} + SUB_ERR_CODE: {type: INT32, desc: sub error code} + EXT_ERR_INFO: {type: INT32, desc: extended error information} + ERR_MSG: {type: STRING, desc: error information sent from the sink during stream projection} + WIFI_INFO: {type: STRING, desc: wifi information when a projection error occurs} + BIZ_PACKAGE_NAME: {type: STRING, desc: package name} + REMOTE_BIZ_TRUNCATED_UDID: {type: STRING, desc: remote truncated UDID} + +NO_DEVICE_FOUND: + __BASE: {type: STATISTIC, level: MINOR, desc: statistics on undiscovered devices} + BT_SWITCH: {type: INT32, desc: bluetooth switch status} + WIFI_INFO: {type: STRING, desc: wifi information when the device is not discovered} + SCAN_TIME: {type: INT32, desc: scan time} + +CAST_ENGINE_EVE: + __BASE: {type: STATISTIC, level: MINOR, desc: projection event} + SEQUENTIAL_ID: {type: STRING, desc: used to associate projection events} + CAST_SESSION_ID: {type: INT32, desc: projection session ID} + ERROR_CODE: {type: INT32, desc: error code} + SUB_ERR_CODE: {type: INT32, desc: sub error code} + EXT_ERR_INFO: {type: INT32, desc: extended error information} + ERR_MSG: {type: STRING, desc: error information sent from the sink during stream projection} + LOCAL_DEVICE_INFO: {type: STRING, desc: local device information record} + REMOTE_DEVICE_INFO: {type: STRING, desc: remote device information record} + CONNECT_INFO: {type: STRING, desc: connect information record} + CAST_STREAM_INFO: {type: STRING, desc: stream information record} + +WIFI_INFO: + __BASE: {type: STATISTIC, level: MINOR, desc: wifi information} + FREQ: {type: INT32, desc: frequency band of the current wifi connection} + RSSI: {type: INT32, desc: signal strength of the current connection} + LINKSPEED: {type: INT32, desc: TX rate of the current connection} + RXLINKSPEED: {type: INT32, desc: RX rate of the current connection} + SNR: {type: INT32, desc: SNR of the current connection} + CHLOAD: {type: INT32, desc: channel loading of the current connected} + FREQ_P2P: {type: INT32, desc: frequency band of the current P2P wifi connection} + RSSI_P2P: {type: INT32, desc: signal strength of the current P2P connection} + LINKSPEED_P2P: {type: INT32, desc: TX rate of the current P2P connection} + RXLINKSPEED_P2P: {type: INT32, desc: RX rate of the current P2P connection} + SNR_P2P: {type: INT32, desc: SNR of the current P2P connection} + CHLOAD_P2P: {type: INT32, desc: channel loading of the current P2P connected} diff --git a/interfaces/inner_api/BUILD.gn b/interfaces/inner_api/BUILD.gn new file mode 100644 index 0000000..cc34dfc --- /dev/null +++ b/interfaces/inner_api/BUILD.gn @@ -0,0 +1,37 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_interfaces_config") { + include_dirs = [ "include" ] +} + +ohos_shared_library("cast_engine_client") { + configs = [ + ":cast_interfaces_config", + "${cast_engine_root}:cast_engine_default_config", + ] + + public_configs = [ ":cast_interfaces_config" ] + + deps = [ + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "samgr:samgr_proxy", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/interfaces/inner_api/include/cast_engine_common.h b/interfaces/inner_api/include/cast_engine_common.h new file mode 100644 index 0000000..357b758 --- /dev/null +++ b/interfaces/inner_api/include/cast_engine_common.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast engine related common data stucture definitions. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_ENGINE_COMMON_H +#define CAST_ENGINE_COMMON_H + +#include +#include +#include + +#include +#define EXPORT __attribute__((visibility("default"))) + +namespace OHOS { +namespace CastEngine { +enum class EXPORT DeviceType { + DEVICE_OTHERS = 0, + DEVICE_SCREEN_PLAYER = 1, + DEVICE_HW_TV = 2, + DEVICE_SOUND_BOX = 3, + DEVICE_HICAR = 4, + DEVICE_MATEBOOK = 5, + DEVICE_PAD = 6, + DEVICE_CAST_PLUS = 7, + DEVICE_TYPE_2IN1 = 8 +}; + +inline bool EXPORT IsDeviceType(int32_t type) +{ + return (type >= static_cast(DeviceType::DEVICE_OTHERS)) && + (type <= static_cast(DeviceType::DEVICE_TYPE_2IN1)); +} + +enum class EXPORT SubDeviceType { + SUB_DEVICE_DEFAULT = 0, + SUB_DEVICE_MATEBOOK_PAD = 51, + SUB_DEVICE_CAST_PLUS_WHITEBOARD = 0x00B2 +}; + +inline bool EXPORT IsSubDeviceType(int32_t type) +{ + return (type == static_cast(SubDeviceType::SUB_DEVICE_DEFAULT)) || + (type == static_cast(SubDeviceType::SUB_DEVICE_MATEBOOK_PAD)) || + (type == static_cast(SubDeviceType::SUB_DEVICE_CAST_PLUS_WHITEBOARD)); +} + +enum class EXPORT TriggerType { + UNSPEC_TAG = 0, + PASSIVE_MATCH_TAG = 1, + ACTIVE_MATCH_TAG = 2, + PASSIVE_BIND_TAG = 3, +}; + +inline bool EXPORT IsTriggerType(int32_t type) +{ + return (type >= static_cast(TriggerType::UNSPEC_TAG)) && + (type <= static_cast(TriggerType::PASSIVE_BIND_TAG)); +} + +enum class EXPORT DeviceState { + CONNECTING, + CONNECTED, + PAUSED, + PLAYING, + DISCONNECTING, + DISCONNECTED, + STREAM, + DEVICE_STATE_MAX, +}; + +const EXPORT std::array(DeviceState::DEVICE_STATE_MAX)> DEVICE_STATE_STRING = { + "CONNECTING", "CONNECTED", "PAUSED", "PLAYING", "DISCONNECTING", "DISCONNECTED", "STREAM", +}; + +inline bool EXPORT IsDeviceState(int32_t state) +{ + return (state >= static_cast(DeviceState::CONNECTING)) && + (state < static_cast(DeviceState::DEVICE_STATE_MAX)); +} + +enum class EXPORT ServiceStatus { + DISCONNECTED, + DISCONNECTING, + CONNECTING, + CONNECTED, +}; + +inline bool EXPORT IsServiceStatus(int32_t status) +{ + return (status >= static_cast(ServiceStatus::DISCONNECTED)) && + (status <= static_cast(ServiceStatus::CONNECTED)); +} + +enum class EXPORT DeviceStatusState { + DEVICE_AVAILABLE, + DEVICE_CONNECTED, + DEVICE_DISCONNECTED, + DEVICE_CONNECT_REQ, +}; + +inline bool EXPORT IsDeviceStatus(int32_t status) +{ + return (status >= static_cast(DeviceStatusState::DEVICE_AVAILABLE)) && + (status <= static_cast(DeviceStatusState::DEVICE_CONNECT_REQ)); +} + +enum class EXPORT PropertyType { + VIDEO_SIZE, + VIDEO_FPS, + WINDOW_SIZE, +}; + +inline bool EXPORT IsPropertyType(int32_t type) +{ + return (type >= static_cast(PropertyType::VIDEO_SIZE)) && + (type <= static_cast(PropertyType::WINDOW_SIZE)); +} + +enum class EXPORT ChannelType { + SOFT_BUS, + LEGACY_CHANNEL, +}; + +inline bool EXPORT IsChannelType(int32_t type) +{ + return (type == static_cast(ChannelType::SOFT_BUS)) || + (type == static_cast(ChannelType::LEGACY_CHANNEL)); +} + +enum class EXPORT ProtocolType { + CAST_PLUS_MIRROR = 1<<0, + CAST_PLUS_STREAM = 1<<1, + MIRACAST = 1<<2, + DLNA = 1<<3, + COOPERATION = 1<<4 +}; + +inline bool EXPORT IsProtocolType(int32_t type) +{ + return (static_cast(type) & (static_cast(ProtocolType::CAST_PLUS_MIRROR) | + static_cast(ProtocolType::CAST_PLUS_STREAM) | + static_cast(ProtocolType::MIRACAST) | + static_cast(ProtocolType::DLNA) | + static_cast(ProtocolType::COOPERATION))) != 0; +} + +enum class EXPORT EndType { + CAST_SINK = 0x10, + CAST_SOURCE = 0x11, +}; + +inline bool EXPORT IsEndType(int32_t type) +{ + return (type == static_cast(EndType::CAST_SINK)) || (type == static_cast(EndType::CAST_SOURCE)); +} + +struct EXPORT DeviceStateInfo { + DeviceState deviceState{ DeviceState::DISCONNECTED }; + std::string deviceId{}; +}; + +struct EXPORT VideoSize { + uint32_t width; + uint32_t height; +}; + +struct EXPORT WindowProperty { + uint32_t startX; + uint32_t startY; + uint32_t width; + uint32_t height; +}; + +struct EXPORT PropertyContainer { + PropertyType type; + union { + VideoSize videoSize; + uint32_t videoFps; + WindowProperty windowProperty; + }; +}; + +enum class EXPORT ColorStandard { + BT709 = 1, + BT601_PAL = 2, + BT601_NTSC = 3, + BT2020 = 6, +}; + +inline bool EXPORT IsColorStandard(int32_t color) +{ + return (color == static_cast(ColorStandard::BT709)) || + (color == static_cast(ColorStandard::BT601_PAL)) || + (color == static_cast(ColorStandard::BT601_NTSC)) || + (color == static_cast(ColorStandard::BT2020)); +} + +enum class EXPORT VideoCodecType { + H264 = 1, + H265 = 2, +}; + +inline bool EXPORT IsVideoCodecType(int32_t type) +{ + return (type == static_cast(VideoCodecType::H264)) || type == static_cast(VideoCodecType::H265); +} + +struct EXPORT AudioProperty { + uint32_t sampleRate; + uint8_t sampleBitWidth; + uint32_t channelConfig; + uint32_t bitrate; + uint32_t codec; +}; + +struct EXPORT VideoProperty { + uint32_t videoWidth{ 0 }; + uint32_t videoHeight{ 0 }; + uint32_t fps{ 0 }; + VideoCodecType codecType{ VideoCodecType::H264 }; + uint32_t gop{ 0 }; + uint32_t bitrate{ 0 }; + uint32_t minBitrate{ 0 }; + uint32_t maxBitrate{ 0 }; + uint32_t dpi{ 0 }; + ColorStandard colorStandard{ ColorStandard::BT709 }; + uint32_t screenWidth{ 0 }; + uint32_t screenHeight{ 0 }; + uint32_t profile{ 0 }; + uint32_t level{ 0 }; +}; + +struct EXPORT CastSessionProperty { + ProtocolType protocolType{ ProtocolType::CAST_PLUS_MIRROR }; + EndType endType{ EndType::CAST_SINK }; + AudioProperty audioProperty; + VideoProperty videoProperty; + WindowProperty windowProperty; +}; + +struct EXPORT CastLocalDevice { + std::string deviceId; + std::string deviceName; + DeviceType deviceType; + SubDeviceType subDeviceType; + std::string ipAddress; + TriggerType triggerType; + std::string authData; +}; + +struct EXPORT AuthInfo { + int authMode; + uint32_t authCode; + std::string deviceId; +}; + +struct EXPORT CastRemoteDevice { + std::string deviceId; + std::string deviceName; + DeviceType deviceType; + SubDeviceType subDeviceType; + std::string ipAddress; + ChannelType channelType; +}; + +enum class EXPORT CastMode { + MIRROR_CAST = 1, + APP_CAST = 2, +}; + +// Parameters for cast mode +const std::string EXPORT KEY_BUNDLE_NAME = "bundleName"; +const std::string EXPORT KEY_PID = "pid"; +const std::string EXPORT KEY_UID = "uid"; +const std::string EXPORT KEY_APP_MIN_COMPATIBLE_VERSION = "minCompatibleVersionCode"; +const std::string EXPORT KEY_APP_TARGET_VERSION = "targetVersion"; +const int EXPORT MAX_DEVICE_NUM = 100; +const int32_t EXPORT MAX_FILE_NUM = 16 * 1024; + +enum class EXPORT EventId { + EVENT_BEGIN = 1, + EVENT_END = 5000, +}; + +inline bool EXPORT IsEventId(int32_t state) +{ + return (state > static_cast(EventId::EVENT_BEGIN)) && (state < static_cast(EventId::EVENT_END)); +} + +struct EXPORT MediaInfo { + std::string mediaId; + std::string mediaName; + std::string mediaUrl; + std::string mediaType; + size_t mediaSize; + uint32_t startPosition; + uint32_t duration; + uint32_t closingCreditsPosition; + std::string albumCoverUrl; + std::string albumTitle; + std::string mediaArtist; + std::string lrcUrl; + std::string lrcContent; + std::string appIconUrl; + std::string appName; +}; + +struct EXPORT MediaInfoHolder { + uint32_t currentIndex; + std::vector mediaInfoList; + uint32_t progressRefreshInterval; +}; + +// > +using FileFdMap = std::map>; + +// +using RcvFdFileMap = std::map; + +enum class EXPORT PlayerStates { + PLAYER_STATE_ERROR = 0, + PLAYER_IDLE = 1, + PLAYER_INITIALIZED = 2, + PLAYER_PREPARING = 3, + PLAYER_PREPARED = 4, + PLAYER_STARTED = 5, + PLAYER_PAUSED = 6, + PLAYER_STOPPED = 7, + PLAYER_PLAYBACK_COMPLETE = 8, + PLAYER_RELEASED = 9 +}; + +enum class EXPORT LoopMode { + LOOP_MODE_SEQUENCE = 1, + LOOP_MODE_SINGLE = 2, + LOOP_MODE_LIST = 3, + LOOP_MODE_SHUFFLE = 4 +}; + +enum class EXPORT PlaybackSpeed { + SPEED_FORWARD_0_75_X = 0, + SPEED_FORWARD_1_00_X = 1, + SPEED_FORWARD_1_25_X = 2, + SPEED_FORWARD_1_75_X = 3, + SPEED_FORWARD_2_00_X = 4 +}; + +inline constexpr int EXPORT INVALID_ID = -1; +inline constexpr int EXPORT INVALID_VALUE = -1; +inline constexpr int EXPORT DECIMALISM = 10; +inline constexpr int EXPORT SUBSYS_CASTPLUS_SYS_ABILITY_ID_BEGIN = 0x00010000; +inline constexpr int EXPORT CAST_ENGINE_SA_ID = 5526; // SUBSYS_CASTPLUS_SYS_ABILITY_ID_BEGIN + 10; // 65546 +inline constexpr int EXPORT SUBSYS_CASTPLUS_SYS_ABILITY_ID_END = 0x0001001f; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/include/cast_engine_errors.h b/interfaces/inner_api/include/cast_engine_errors.h new file mode 100644 index 0000000..67419e0 --- /dev/null +++ b/interfaces/inner_api/include/cast_engine_errors.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply errors definition for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#ifndef CAST_ENGINE_ERRORS_H +#define CAST_ENGINE_ERRORS_H + +#include +#include "errors.h" +#include "cast_engine_common.h" + +namespace OHOS { +namespace CastEngine { +constexpr int32_t EXPORT CAST_ENGINE_ERROR = -1; +constexpr int32_t EXPORT CAST_ENGINE_SUCCESS = 0; +constexpr int32_t EXPORT CAST_ENGINE_ERROR_BASE = 1000; +constexpr int32_t EXPORT ERR_NO_MEMORY = -(CAST_ENGINE_ERROR_BASE + 1); +constexpr int32_t EXPORT ERR_INVALID_PARAM = -(CAST_ENGINE_ERROR_BASE + 2); +constexpr int32_t EXPORT ERR_NO_PERMISSION = -(CAST_ENGINE_ERROR_BASE + 3); +constexpr int32_t EXPORT ERR_SESSION_NOT_EXIST = -(CAST_ENGINE_ERROR_BASE + 4); +constexpr int32_t EXPORT ERR_SERVICE_STATE_NOT_MATCH = -(CAST_ENGINE_ERROR_BASE + 5); +constexpr int32_t EXPORT ERR_SESSION_STATE_NOT_MATCH = -(CAST_ENGINE_ERROR_BASE + 6); +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_ERRORS_H \ No newline at end of file diff --git a/interfaces/inner_api/include/cast_session_manager.h b/interfaces/inner_api/include/cast_session_manager.h new file mode 100644 index 0000000..1bdc9f8 --- /dev/null +++ b/interfaces/inner_api/include/cast_session_manager.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast session manager apis. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_SESSION_MANAGER_H +#define CAST_SESSION_MANAGER_H + +#include +#include +#include "cast_engine_common.h" +#include "i_cast_session.h" +#include "i_cast_session_manager_adaptor.h" +#include "i_cast_session_manager_listener.h" +#include "iremote_object.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class EXPORT CastSessionManager { +public: + static CastSessionManager &GetInstance(); + + CastSessionManager(const CastSessionManager &) = delete; + CastSessionManager &operator=(const CastSessionManager &) = delete; + CastSessionManager(CastSessionManager &&) = delete; + CastSessionManager &operator=(CastSessionManager &&) = delete; + ~CastSessionManager() = default; + + int32_t RegisterListener(std::shared_ptr listener); + int32_t UnregisterListener(); + int32_t Release(); + int32_t SetLocalDevice(const CastLocalDevice &localDevice); + int32_t CreateCastSession(const CastSessionProperty &property, std::shared_ptr &castSession); + int32_t SetSinkSessionCapacity(int sessionCapacity); + int32_t StartDiscovery(int protocols); + int32_t SetDiscoverable(bool enable); + int32_t StopDiscovery(); + void ReleaseClientResources(); + + int32_t GetCastSession(std::string sessionId, std::shared_ptr &castSession); +private: + class CastEngineServiceDeathRecipient : public IRemoteObject::DeathRecipient { + public: + CastEngineServiceDeathRecipient(std::shared_ptr listener) + : listener_(listener) {}; + void OnRemoteDied(const wptr &object) override; + std::shared_ptr GetListener() + { + return listener_; + } + + private: + std::shared_ptr listener_; + }; + + CastSessionManager(); + void ReleaseServiceDeathRecipient(); + std::shared_ptr GetAdaptor(); + + std::mutex mutex_; + std::shared_ptr adaptor_; + sptr deathRecipient_{ nullptr }; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/interfaces/inner_api/include/i_cast_session.h b/interfaces/inner_api/include/i_cast_session.h new file mode 100644 index 0000000..5d07c50 --- /dev/null +++ b/interfaces/inner_api/include/i_cast_session.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast session interface. + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef I_CAST_SESSION_H +#define I_CAST_SESSION_H + +#include "cast_engine_common.h" +#include "oh_remote_control_event.h" +#include "i_stream_player.h" +#include "i_mirror_player.h" + +namespace OHOS { +namespace CastEngine { +class EXPORT ICastSessionListener { +public: + ICastSessionListener() = default; + ICastSessionListener(const ICastSessionListener &) = delete; + ICastSessionListener &operator = (const ICastSessionListener &) = delete; + ICastSessionListener(ICastSessionListener &&) = delete; + ICastSessionListener &operator = (ICastSessionListener &&) = delete; + virtual ~ICastSessionListener() = default; + + virtual void OnDeviceState(const DeviceStateInfo &stateInfo) = 0; + virtual void OnEvent(const EventId &eventId, const std::string &jsonParam) = 0; +}; + +class EXPORT ICastSession { +public: + ICastSession() = default; + ICastSession(const ICastSession &) = delete; + ICastSession &operator = (const ICastSession &) = delete; + ICastSession(ICastSession &&) = delete; + ICastSession &operator = (ICastSession &&) = delete; + virtual ~ICastSession() = default; + + virtual int32_t RegisterListener(std::shared_ptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t AddDevice(const CastRemoteDevice &remoteDevice) = 0; + virtual int32_t RemoveDevice(const std::string &deviceId) = 0; + virtual int32_t StartAuth(const AuthInfo &authInfo) = 0; + virtual int32_t GetSessionId(std::string &sessionId) = 0; + virtual int32_t SetSessionProperty(const CastSessionProperty &property) = 0; + virtual int32_t CreateMirrorPlayer(std::shared_ptr &mirrorPlayer) = 0; + virtual int32_t CreateStreamPlayer(std::shared_ptr &streamPlayer) = 0; + virtual int32_t NotifyEvent(EventId eventId, std::string &jsonParam) = 0; + virtual int32_t SetCastMode(CastMode mode, std::string &jsonParam) = 0; + virtual int32_t Release() = 0; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/include/i_cast_session_manager_adaptor.h b/interfaces/inner_api/include/i_cast_session_manager_adaptor.h new file mode 100644 index 0000000..f7c5e15 --- /dev/null +++ b/interfaces/inner_api/include/i_cast_session_manager_adaptor.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager base adaptor + * Author: zhangge + * Create: 2022-5-29 + */ + +#ifndef I_CAST_SESSION_MANAGER_ADAPTOR_H +#define I_CAST_SESSION_MANAGER_ADAPTOR_H + +#include + +#include "cast_engine_common.h" +#include "i_cast_session.h" +#include "i_cast_session_manager_listener.h" +#include "iremote_object.h" + +namespace OHOS { +namespace CastEngine { +class EXPORT ICastSessionManagerAdaptor { +public: + ICastSessionManagerAdaptor() = default; + ICastSessionManagerAdaptor(const ICastSessionManagerAdaptor &) = delete; + ICastSessionManagerAdaptor &operator = (const ICastSessionManagerAdaptor &) = delete; + ICastSessionManagerAdaptor(ICastSessionManagerAdaptor &&) = delete; + ICastSessionManagerAdaptor &operator = (ICastSessionManagerAdaptor &&) = delete; + virtual ~ICastSessionManagerAdaptor() = default; + + virtual int32_t RegisterListener(std::shared_ptr listener, + sptr deathRecipient) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t Release() = 0; + virtual int32_t SetLocalDevice(const CastLocalDevice &localDevice) = 0; + virtual int32_t CreateCastSession(const CastSessionProperty &property, + std::shared_ptr &castSession) = 0; + virtual int32_t SetSinkSessionCapacity(int sessionCapacity) = 0; + virtual int32_t StartDiscovery(int protocols) = 0; + virtual int32_t SetDiscoverable(bool enable) = 0; + virtual int32_t StopDiscovery() = 0; + virtual int32_t GetCastSession(std::string sessionId, std::shared_ptr &castSession) = 0; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif // I_CAST_SESSION_MANAGER_ADAPTOR_H \ No newline at end of file diff --git a/interfaces/inner_api/include/i_cast_session_manager_listener.h b/interfaces/inner_api/include/i_cast_session_manager_listener.h new file mode 100644 index 0000000..e1e18df --- /dev/null +++ b/interfaces/inner_api/include/i_cast_session_manager_listener.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager listener apis. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef I_CAST_SESSION_MANAGER_LISTENER_H +#define I_CAST_SESSION_MANAGER_LISTENER_H + +#include "cast_engine_common.h" +#include "i_cast_session.h" + +namespace OHOS { +namespace CastEngine { +class EXPORT ICastSessionManagerListener { +public: + ICastSessionManagerListener() = default; + ICastSessionManagerListener(const ICastSessionManagerListener &) = delete; + ICastSessionManagerListener &operator=(const ICastSessionManagerListener &) = delete; + ICastSessionManagerListener(ICastSessionManagerListener &&) = delete; + ICastSessionManagerListener &operator=(ICastSessionManagerListener &&) = delete; + virtual ~ICastSessionManagerListener() = default; + + virtual void OnDeviceFound(const std::vector &deviceList) = 0; + virtual void OnDeviceOffline(const std::string &deviceId) = 0; + virtual void OnSessionCreated(const std::shared_ptr &castSession) = 0; + virtual void OnServiceDied() = 0; +}; +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/inner_api/include/i_mirror_player.h b/interfaces/inner_api/include/i_mirror_player.h new file mode 100644 index 0000000..5ed01b0 --- /dev/null +++ b/interfaces/inner_api/include/i_mirror_player.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Cast mirror player interface. + * Author: zhangjingnan + * Create: 2023-05-27 + */ + +#ifndef I_CAST_MIRROR_PLAYER_H +#define I_CAST_MIRROR_PLAYER_H + +#include "cast_engine_common.h" +#include "oh_remote_control_event.h" + +namespace OHOS { +namespace CastEngine { +class EXPORT IMirrorPlayer { +public: + IMirrorPlayer() = default; + IMirrorPlayer(const IMirrorPlayer &) = delete; + IMirrorPlayer &operator = (const IMirrorPlayer &) = delete; + IMirrorPlayer(IMirrorPlayer &&) = delete; + IMirrorPlayer &operator = (IMirrorPlayer &&) = delete; + virtual ~IMirrorPlayer() = default; + + virtual int32_t Play(const std::string &deviceId) = 0; + virtual int32_t Pause(const std::string &deviceId) = 0; + virtual int32_t SetSurface(const std::string &surfaceId) = 0; + virtual int32_t DeliverInputEvent(OHRemoteControlEvent event) = 0; + virtual int32_t Release() = 0; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/include/i_stream_player.h b/interfaces/inner_api/include/i_stream_player.h new file mode 100644 index 0000000..a437565 --- /dev/null +++ b/interfaces/inner_api/include/i_stream_player.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Stream Player interface. + * Author: huangchanggui + * Create: 2023-01-11 + */ + +#ifndef I_STREAM_PLAYER_H +#define I_STREAM_PLAYER_H + +#include "cast_engine_common.h" + +namespace OHOS { +namespace CastEngine { +class EXPORT IStreamPlayerListener { +public: + IStreamPlayerListener() = default; + IStreamPlayerListener(const IStreamPlayerListener &) = delete; + IStreamPlayerListener &operator=(const IStreamPlayerListener &) = delete; + IStreamPlayerListener(IStreamPlayerListener &&) = delete; + IStreamPlayerListener &operator=(IStreamPlayerListener &&) = delete; + virtual ~IStreamPlayerListener() = default; + + virtual void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) = 0; + virtual void OnPositionChanged(int position, int bufferPosition, int duration) = 0; + virtual void OnMediaItemChanged(const MediaInfo &mediaInfo) = 0; + virtual void OnVolumeChanged(int volume, int maxVolume) = 0; + virtual void OnLoopModeChanged(const LoopMode loopMode) = 0; + virtual void OnPlaySpeedChanged(const PlaybackSpeed speed) = 0; + virtual void OnPlayerError(int errorCode, const std::string &errorMsg) = 0; + virtual void OnVideoSizeChanged(int width, int height) = 0; + virtual void OnNextRequest() = 0; + virtual void OnPreviousRequest() = 0; + virtual void OnSeekDone(int position) = 0; + virtual void OnEndOfStream(int isLooping) = 0; + virtual void OnPlayRequest(const MediaInfo &mediaInfo) = 0; +}; + +class EXPORT IStreamPlayer { +public: + IStreamPlayer() = default; + IStreamPlayer(const IStreamPlayer &) = delete; + IStreamPlayer &operator=(const IStreamPlayer &) = delete; + IStreamPlayer(IStreamPlayer &&) = delete; + IStreamPlayer &operator=(IStreamPlayer &&) = delete; + virtual ~IStreamPlayer() = default; + + virtual int32_t RegisterListener(std::shared_ptr listener) = 0; + virtual int32_t UnregisterListener() = 0; + virtual int32_t SetSurface(const std::string &surfaceId) = 0; + virtual int32_t Load(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(const MediaInfo &mediaInfo) = 0; + virtual int32_t Play(int index) = 0; + virtual int32_t Play() = 0; + virtual int32_t Pause() = 0; + virtual int32_t Stop() = 0; + virtual int32_t Next() = 0; + virtual int32_t Previous() = 0; + virtual int32_t Seek(int position) = 0; + virtual int32_t FastForward(int delta) = 0; + virtual int32_t FastRewind(int delta) = 0; + virtual int32_t SetVolume(int volume) = 0; + virtual int32_t SetLoopMode(const LoopMode mode) = 0; + virtual int32_t SetSpeed(const PlaybackSpeed speed) = 0; + virtual int32_t GetPlayerStatus(PlayerStates &playerStates) = 0; + virtual int32_t GetPosition(int &position) = 0; + virtual int32_t GetDuration(int &duration) = 0; + virtual int32_t GetVolume(int &volume, int &maxVolume) = 0; + virtual int32_t GetLoopMode(LoopMode &loopMode) = 0; + virtual int32_t GetPlaySpeed(PlaybackSpeed &playbackSpeed) = 0; + virtual int32_t GetMediaInfoHolder(MediaInfoHolder &mediaInfoHolder) = 0; + virtual int32_t Release() = 0; +}; +} // namespace CastEngine +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/include/oh_remote_control_event.h b/interfaces/inner_api/include/oh_remote_control_event.h new file mode 100644 index 0000000..c283fb6 --- /dev/null +++ b/interfaces/inner_api/include/oh_remote_control_event.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Remote Control related data from OH XComponent structure definitions. + * Author: mayihao + * Create: 2022-09-14 + */ + + +#ifndef OH_REMOTE_CONTROL_EVENT_H +#define OH_REMOTE_CONTROL_EVENT_H + +#include +#include "cast_engine_common.h" + +namespace OHOS { +namespace CastEngine { +enum class EXPORT XcomponentEventType { + REMOTECONTROL_TOUCH, + REMOTECONTROL_MOUSE, + REMOTECONTROL_PEN, + REMOTECONTROL_WHEEL, + REMOTECONTROL_KEY, + REMOTECONTROL_INPUT_METHOD, + REMOTECONTROL_VIRTUAL_KEY, + REMOTECONTROL_INVALID_EVENT, +}; + +enum EXPORT OHNativeXcomponentResult { + OH_NATIVEXCOMPONENT_RESULT_SUCCESS = 0, + OH_NATIVEXCOMPONENT_RESULT_FAILED = -1, + OH_NATIVEXCOMPONENT_RESULT_BAD_PARAMETER = -2, +}; + +enum EXPORT OHNativeXcomponentTouchEventType { + OH_NATIVEXCOMPONENT_TOUCH_DOWN = 0, + OH_NATIVEXCOMPONENT_TOUCH_UP, + OH_NATIVEXCOMPONENT_TOUCH_MOVE, + OH_NATIVEXCOMPONENT_TOUCH_CANCEL, +}; + +enum EXPORT OHNativeXcomponentMouseEventAction { + OH_NATIVEXCOMPONENT_MOUSE_PRESS = 0, + OH_NATIVEXCOMPONENT_MOUSE_RELEASE, + OH_NATIVEXCOMPONENT_MOUSE_MOVE, + OH_NATIVEXCOMPONENT_MOUSE_NONE, +}; + +enum EXPORT OHNativeXcomponentKeyEventType { + OH_NATIVEXCOMPONENT_KEY_DOWN = 0, + OH_NATIVEXCOMPONENT_KEY_UP, +}; + +enum EXPORT OHNativeXcomponentMouseEventButton { + OH_NATIVEXCOMPONENT_LEFT_BUTTON = 0, + OH_NATIVEXCOMPONENT_MIDDLE_BUTTON, + OH_NATIVEXCOMPONENT_RIGHT_BUTTON, +}; + +enum EXPORT OHNativeXcomponentInputMethodEventType { + OH_NATIVEXCOMPONENT_INPUT_CONTENT = 0, + OH_NATIVEXCOMPONENT_INPUT_FOCUS, +}; + +enum EXPORT OHNativeXcomponentWheelEventDirection { + OH_NATIVEXCOMPONENT_WHEEL_VERTICAL = 0, + OH_NATIVEXCOMPONENT_WHEEL_HORIZONTAL +}; + +enum EXPORT OHNativeXcomponentVirtualKeyEventType { + OH_NATIVEXCOMPONENT_VIRTUALKEY_BACK = 0, + OH_NATIVEXCOMPONENT_VIRTUALKEY_HOME, + OH_NATIVEXCOMPONENT_VIRTUALKEY_RECENT_APP, + OH_NATIVEXCOMPONENT_VIRTUALKEY_QUICK_SETTING +}; + +const uint32_t EXPORT OH_MAX_TOUCH_POINTS_NUMBER = 10; +const uint32_t EXPORT OH_MAX_CONTENT_LEN = 472; + +struct EXPORT OHNativeXcomponentTouchPoint { + int32_t id = 0; // Unique identifier of a finger. + float screenX = 0.0; // X coordinate of the touch point relative to the left edge of the screen. + float screenY = 0.0; // Y coordinate of the touch point relative to the upper edge of the screen. + float x = 0.0; // X coordinate of the touch point relative to the left edge of the element to touch. + float y = 0.0; // Y coordinate of the touch point relative to the upper edge of the element to touch. + OHNativeXcomponentTouchEventType type; + double size = 0.0; // Contact area between the finger pad and the screen. + float force = 0.0; // Pressure of the current touch event. + int64_t timeStamp = 0; // Timestamp of the current touch event. + bool isPressed = false; // Whether the current point is pressed. +}; + +struct EXPORT OHNativeXcomponentTouchEvent { + int32_t id = 0; // Unique identifier of a finger. + float screenX = 0.0; // X coordinate of the touch point relative to the left edge of the screen. + float screenY = 0.0; // Y coordinate of the touch point relative to the upper edge of the screen. + float x = 0.0; // X coordinate of the touch point relative to the left edge of the element to touch. + float y = 0.0; // Y coordinate of the touch point relative to the upper edge of the element to touch. + OHNativeXcomponentTouchEventType type; + double size = 0.0; // Contact area between the finger pad and the screen. + float force = 0.0; // Pressure of the current touch event. + int64_t deviceId = 0; // ID of the device where the current touch event is generated. + int64_t timeStamp = 0; // Timestamp of the current touch event. + uint32_t numPoints = 0; // Number of current touch points. + OHNativeXcomponentTouchPoint touchPoints[OH_MAX_TOUCH_POINTS_NUMBER]; // Array of the current touch points. +}; + +struct EXPORT OHNativeXcomponentMouseEvent { + float x = 0.0; // X coordinate of the mouse point relative to the left edge of the element to mouse. + float y = 0.0; // Y coordinate of the mouse point relative to the upper edge of the element to mouse. + float screenX = 0.0; // X coordinate of the mouse point relative to the left edge of the screen. + float screenY = 0.0; // Y coordinate of the mouse point relative to the upper edge of the screen. + int64_t timestamp = 0; // Timestamp of the current mouse event. + OHNativeXcomponentMouseEventAction action; + OHNativeXcomponentMouseEventButton button; +}; + +struct EXPORT OHNativeXcomponentKeyEvent { + uint8_t reserved; + uint16_t keyCode1; // the first key code + uint16_t keyCode2; // the second key code + uint32_t metaState; // whether meta keys is pressed + OHNativeXcomponentKeyEventType type; +}; + +struct EXPORT OHNativeXcomponentContentEvent { + uint16_t msgLen; + char inputText[OH_MAX_CONTENT_LEN]; +}; + +struct EXPORT OHNativeXcomponentFocusEvent { + uint8_t focusStat; // is focus on + double cursorX1; // The X position of the upper-left corner of the cursor + double cursorY1; // The Y position of the upper-left corner of the cursor + double cursorX2; // The X position of the lowwer-right corner of the cursor + double cursorY2; // The Y position of the lowwer-right corner of the cursor +}; + +struct EXPORT OHNativeXcomponentInputMethodEvent { + OHNativeXcomponentInputMethodEventType type; + union { + OHNativeXcomponentContentEvent contentEvent; + OHNativeXcomponentFocusEvent focusEvent; + }; +}; + +struct EXPORT OHNativeXcomponentWheelEvent { + OHNativeXcomponentWheelEventDirection direction; + uint8_t indication = 1; // 0b0:Scrolling to the right/Scrolling down, 0b1:Scrolling to the left/Scrolling up + uint8_t scrollUnit = 2; // 0b00:the unit is a pixel, 0b01:the unit is a mouse notch, 0b10-0b11:Reserved + uint16_t wheelDis; // wheel distance + float x; // X-coordinate when wheel button down + float y; // Y-coordinate when wheel button down +}; + +struct EXPORT OHNativeXcomponentVirtualKeyEvent { + OHNativeXcomponentVirtualKeyEventType type; + float x; + float y; +}; + +struct EXPORT OHRemoteControlEvent { + OHRemoteControlEvent() {}; + XcomponentEventType eventType = XcomponentEventType::REMOTECONTROL_INVALID_EVENT; + union { + OHNativeXcomponentTouchEvent touchEvent; + OHNativeXcomponentMouseEvent mouseEvent; + OHNativeXcomponentKeyEvent keyEvent; + OHNativeXcomponentInputMethodEvent inputMethodEvent; + OHNativeXcomponentWheelEvent wheelEvent; + OHNativeXcomponentVirtualKeyEvent virtualKeyEvent; + }; +}; +} // namespace CastEngine +} // namespace OHOS +#endif diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn new file mode 100644 index 0000000..79afef9 --- /dev/null +++ b/interfaces/kits/js/BUILD.gn @@ -0,0 +1,52 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_config") { + include_dirs = [ + "include", + "${cast_engine_interfaces}/inner_api:cast_interfaces_config" + ] +} + +ohos_shared_library("cast") { + sources = [ + "src/napi_cast_session.cpp", + "src/napi_cast_session_listener.cpp", + "src/napi_cast_session_manager.cpp", + "src/napi_cast_session_manager_listener.cpp", + "src/napi_castengine_utils.cpp", + "src/native_module.cpp", + "src/napi_mirror_player.cpp", + "src/napi_stream_player.cpp", + "src/napi_stream_player_listener.cpp", + "src/napi_callback.cpp", + "src/napi_async_work.cpp", + "src/napi_castengine_enum.cpp" + ] + + configs = [ + ":cast_config", + "${cast_engine_root}:cast_engine_default_config" + ] + + deps = [ + "${cast_engine_common}:cast_engine_common_sources", + "${cast_engine_interfaces}/inner_api:cast_engine_client", + ] + + external_deps = [ + "hilog:libhilog", + "ipc:ipc_core", + "napi:ace_napi" + ] + + relative_install_dir = "module" + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/interfaces/kits/js/include/napi_async_work.h b/interfaces/kits/js/include/napi_async_work.h new file mode 100644 index 0000000..d9b1c04 --- /dev/null +++ b/interfaces/kits/js/include/napi_async_work.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi async work for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#ifndef NAPI_CAST_ASYNC_WORK_H +#define NAPI_CAST_ASYNC_WORK_H + +#include +#include +#include +#include +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +using NapiCbInfoParser = std::function; +using NapiAsyncExecute = std::function; +using NapiAsyncComplete = std::function; + +struct NapiAsyncTask { + virtual ~NapiAsyncTask(); + void GetJSInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parser = NapiCbInfoParser(), + bool sync = false); + + napi_env env = nullptr; + napi_value output = nullptr; + napi_status status = napi_invalid_arg; + std::string errMessage; + int32_t errCode; + void *native = nullptr; + std::string taskName; + +private: + napi_deferred deferred = nullptr; + napi_async_work work = nullptr; + napi_ref callbackRef = nullptr; + NapiAsyncExecute execute = nullptr; + NapiAsyncComplete complete = nullptr; + std::shared_ptr hold; /* cross thread data */ + + static constexpr size_t ARGC_MAX = 4; + friend class NapiAsyncWork; +}; + +class NapiAsyncWork { +public: + static napi_value Enqueue(napi_env env, std::shared_ptr ctxt, const std::string &name, + NapiAsyncExecute execute = NapiAsyncExecute(), NapiAsyncComplete complete = NapiAsyncComplete()); + +private: + static void GenerateOutput(NapiAsyncTask *napiAsyncTask); + enum { + RESULT_ERROR = 0, + RESULT_DATA = 1, + RESULT_ALL = 2 + }; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif // NAPI_CAST_ASYNC_WORK_H \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_callback.h b/interfaces/kits/js/include/napi_callback.h new file mode 100644 index 0000000..0756083 --- /dev/null +++ b/interfaces/kits/js/include/napi_callback.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi callback for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#ifndef NAPI_CALLBACK_H +#define NAPI_CALLBACK_H + +#include +#include "napi/native_api.h" +#include "napi/native_common.h" +#include "napi/native_node_api.h" +#include "uv.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class NapiCallback final { +public: + using NapiArgsGetter = std::function; + + explicit NapiCallback(napi_env env); + ~NapiCallback(); + + napi_env GetEnv() const; + + void Call(napi_ref method, NapiArgsGetter getter); + +private: + static void AfterWorkCallback(uv_work_t *work, int status); + + struct DataContext { + napi_env env; + napi_ref method; + NapiArgsGetter getter; + }; + napi_env env_ = nullptr; + uv_loop_s *loop_ = nullptr; + + static constexpr size_t ARGC_MAX = 6; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_cast_session.h b/interfaces/kits/js/include/napi_cast_session.h new file mode 100644 index 0000000..b988760 --- /dev/null +++ b/interfaces/kits/js/include/napi_cast_session.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface for cast session. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#ifndef NAPI_CAST_SESSION_H_ +#define NAPI_CAST_SESSION_H_ + +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_errors.h" +#include "cast_engine_errors.h" +#include "i_cast_session.h" +#include "napi_cast_session_listener.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class EXPORT NapiCastSession { +public: + using OnEventHandlerType = std::function; + using OffEventHandlerType = std::function; + + static void DefineCastSessionJSClass(napi_env env); + static napi_status CreateNapiCastSession(napi_env env, std::shared_ptr session, napi_value &out); + std::shared_ptr NapiListenerGetter(); + void NapiListenerSetter(std::shared_ptr listener); + + NapiCastSession(std::shared_ptr session) : session_(session) {} + NapiCastSession() = default; + ~NapiCastSession() = default; + std::shared_ptr GetCastSession() + { + std::lock_guard lock(mutex_); + return session_; + } + void Reset() + { + std::lock_guard lock(mutex_); + session_.reset(); + listener_.reset(); + } + +private: + static napi_value NapiCastSessionConstructor(napi_env env, napi_callback_info info); + static napi_value AddDevice(napi_env env, napi_callback_info info); + static napi_value RemoveDevice(napi_env env, napi_callback_info info); + static napi_value GetSessionId(napi_env env, napi_callback_info info); + static napi_value SetSessionProperty(napi_env env, napi_callback_info info); + static napi_value CreateMirrorPlayer(napi_env env, napi_callback_info info); + static napi_value CreateStreamPlayer(napi_env env, napi_callback_info info); + static napi_value SetCastMode(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + + static napi_status OnInnerEvent(napi_env env, napi_value callback, NapiCastSession *napiSession); + static napi_status OnDeviceState(napi_env env, napi_value callback, NapiCastSession *napiSession); + + static napi_status OffInnerEvent(napi_env env, napi_value callback, NapiCastSession *napiSession); + static napi_status OffDeviceState(napi_env env, napi_value callback, NapiCastSession *napiSession); + + static NapiCastSession *GetNapiCastSession(napi_env env, napi_callback_info info); + static napi_status RegisterNativeSessionListener(NapiCastSession *napiSession); + + static std::map> eventHandlers_; + std::mutex mutex_; + std::shared_ptr session_; + std::shared_ptr listener_; + static thread_local napi_ref consRef_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_cast_session_listener.h b/interfaces/kits/js/include/napi_cast_session_listener.h new file mode 100644 index 0000000..e596071 --- /dev/null +++ b/interfaces/kits/js/include/napi_cast_session_listener.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session listener for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#ifndef NAPI_CAST_SESSION_LISTENER_H +#define NAPI_CAST_SESSION_LISTENER_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include +#include "i_cast_session.h" +#include "napi_callback.h" +#include "cast_engine_common.h" +#include "napi_castengine_utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class NapiCastSessionListener : public ICastSessionListener { +public: + using NapiArgsGetter = std::function; + enum { + EVENT_ON_EVENT, + EVENT_DEVICE_STATE, + EVENT_TYPE_MAX + }; + NapiCastSessionListener() {}; + ~NapiCastSessionListener() override; + + void OnDeviceState(const DeviceStateInfo &stateEvent) override; + void OnEvent(const EventId &eventId, const std::string &jsonParam) override; + + napi_status AddCallback(napi_env env, int32_t event, napi_value callback); + napi_status RemoveCallback(napi_env env, int32_t event, napi_value callback); + +private: + void HandleEvent(int32_t event, NapiArgsGetter getter); + napi_status ClearCallback(napi_env env); + + std::mutex lock_; + std::shared_ptr callback_; + std::list callbacks_[EVENT_TYPE_MAX] {}; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_cast_session_manager.h b/interfaces/kits/js/include/napi_cast_session_manager.h new file mode 100644 index 0000000..8c6fe19 --- /dev/null +++ b/interfaces/kits/js/include/napi_cast_session_manager.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface for cast session manager. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#ifndef NAPI_CAST_SESSION_MANAGER_H_ +#define NAPI_CAST_SESSION_MANAGER_H_ + +#include +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_errors.h" +#include "cast_engine_errors.h" +#include "cast_session_manager.h" +#include "napi_cast_session_manager_listener.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class EXPORT NapiCastSessionManager { +public: + using OnEventHandlerType = std::function; + using OffEventHandlerType = std::function; + + static napi_value Init(napi_env env, napi_value exports); + +private: + static napi_value StartDiscovery(napi_env env, napi_callback_info info); + static napi_value StopDiscovery(napi_env env, napi_callback_info info); + static napi_value SetDiscoverable(napi_env env, napi_callback_info info); + static napi_value CreateCastSession(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + + static napi_status OnServiceDied(napi_env env, napi_value callback); + static napi_status OnDeviceFound(napi_env env, napi_value callback); + static napi_status OnSessionCreated(napi_env env, napi_value callback); + + static napi_status OffServiceDie(napi_env env, napi_value callback); + static napi_status OffDeviceFound(napi_env env, napi_value callback); + static napi_status OffSessionCreated(napi_env env, napi_value callback); + + static napi_status RegisterNativeSessionManagerListener(); + static std::map> eventHandlers_; + static std::shared_ptr listener_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_cast_session_manager_listener.h b/interfaces/kits/js/include/napi_cast_session_manager_listener.h new file mode 100644 index 0000000..3bc065a --- /dev/null +++ b/interfaces/kits/js/include/napi_cast_session_manager_listener.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager listener for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#ifndef NAPI_CAST_SESSION_MANAGER_LISTENER_H +#define NAPI_CAST_SESSION_MANAGER_LISTENER_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include +#include "cast_engine_common.h" +#include "i_cast_session_manager_listener.h" +#include "napi_callback.h" +#include "napi_castengine_utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class NapiCastSessionManagerListener : public ICastSessionManagerListener { +public: + using NapiArgsGetter = std::function; + enum { + EVENT_SERVICE_DIED, + EVENT_DEVICE_FOUND, + EVENT_SESSION_CREATE, + EVENT_TYPE_MAX + }; + NapiCastSessionManagerListener() {}; + ~NapiCastSessionManagerListener() override; + + void OnDeviceFound(const std::vector &deviceList) override; + void OnDeviceOffline(const std::string &deviceId) override; + void OnSessionCreated(const std::shared_ptr &castSession) override; + void OnServiceDied() override; + + napi_status AddCallback(napi_env env, int32_t event, napi_value callback); + napi_status RemoveCallback(napi_env env, int32_t event, napi_value callback); + +private: + void HandleEvent(int32_t event, NapiArgsGetter getter); + napi_status ClearCallback(napi_env env); + + std::mutex lock_; + std::shared_ptr callback_; + std::list callbacks_[EVENT_TYPE_MAX] {}; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_castengine_enum.h b/interfaces/kits/js/include/napi_castengine_enum.h new file mode 100644 index 0000000..057cd19 --- /dev/null +++ b/interfaces/kits/js/include/napi_castengine_enum.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi nums for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#ifndef NAPI_CASTENGINE_CONST_PROPERTIES_H +#define NAPI_CASTENGINE_CONST_PROPERTIES_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +napi_status InitEnums(napi_env env, napi_value exports); +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_castengine_utils.h b/interfaces/kits/js/include/napi_castengine_utils.h new file mode 100644 index 0000000..d891501 --- /dev/null +++ b/interfaces/kits/js/include/napi_castengine_utils.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply utils for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#ifndef NAPI_CASTENGINE_UTILS_H +#define NAPI_CASTENGINE_UTILS_H + +#include +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "i_cast_session.h" +#include "oh_remote_control_event.h" + +#define CHECK_ARGS_RETURN_VOID(context, condition, message, code) \ + do { \ + if (!(condition)) { \ + (context)->status = napi_invalid_arg; \ + (context)->errMessage = std::string(message); \ + (context)->errCode = code; \ + CLOGE("(" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +#define CHECK_STATUS_RETURN_VOID(context, message, code) \ + do { \ + if ((context)->status != napi_ok) { \ + (context)->errMessage = std::string(message); \ + (context)->errCode = code; \ + CLOGE("(context->status == napi_ok) failed: " message); \ + return; \ + } \ + } while (0) + +#define CHECK_RETURN_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + CLOGE("(" #condition ") failed: " message); \ + return; \ + } \ + } while (0) + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +constexpr int32_t CALLBACK_ARGC_ZERO = 0; +constexpr int32_t CALLBACK_ARGC_ONE = 1; +constexpr int32_t CALLBACK_ARGC_TWO = 2; +constexpr int32_t CALLBACK_ARGC_THERE = 3; +constexpr int32_t CALLBACK_ARGC_FOUR = 4; + +std::string ParseString(napi_env env, napi_value args); +int32_t ParseInt32(napi_env env, napi_value args); +bool ParseBool(napi_env env, napi_value args); +std::string JsObjectToString(napi_env env, napi_value &object, const char *fieldStr); +int32_t JsObjectToInt32(napi_env env, napi_value &object, const char *fieldStr); +bool JsObjectToBool(napi_env env, napi_value &object, const char *fieldStr); +uint32_t JsObjectToUint32(napi_env env, napi_value &object, const char *fieldStr); +double JsObjectToDouble(napi_env env, napi_value &object, const char *fieldStr); +int64_t JsObjectToInt64(napi_env env, napi_value &object, const char *fieldStr); + +napi_value ConvertDeviceListToJS(napi_env env, const std::vector &devices); +napi_value ConvertCastSessionToJS(napi_env env, const std::shared_ptr &castSession); +napi_value ConvertDeviceStateInfoToJS(napi_env env, const DeviceStateInfo &stateEvent); +napi_value ConvertMediaInfoToJS(napi_env env, const MediaInfo &mediaInfo); +napi_value ConvertMediaInfoHolderToJS(napi_env env, const MediaInfoHolder &mediaInfoHolder); +napi_value ConvertCastRemoteDeviceToJS(napi_env env, const CastRemoteDevice &castRemoteDevice); + +CastRemoteDevice GetCastRemoteDeviceFromJS(napi_env env, napi_value &object); +CastSessionProperty GetCastSessionPropertyFromJS(napi_env env, napi_value &object); +AudioProperty GetAudioPropertyFromJS(napi_env env, napi_value &object); +VideoProperty GetVideoPropertyFromJS(napi_env env, napi_value &object); +WindowProperty GetWindowPropertyFromJS(napi_env env, napi_value &object); +bool GetMediaInfoFromJS(napi_env env, napi_value &object, MediaInfo &mediaInfo); +bool GetProtocolTypesFromJS(napi_env env, napi_value &object, int &protocolTypes); +bool GetMediaInfoHolderFromJS(napi_env env, napi_value &object, MediaInfoHolder &mediaInfoHolder); + +bool GetJSFuncParams(napi_env env, napi_callback_info info, napi_value argv[], size_t expectedArgc, + napi_valuetype expectedTypes[]); +bool CheckJSParamsType(napi_env env, napi_value argv[], size_t expectedArgc, napi_valuetype expectedTypes[]); +void CallJSFunc(napi_env env, napi_ref func, size_t argc, napi_value argv[]); +napi_value GetUndefinedValue(napi_env env); +bool Equals(napi_env env, napi_value value, napi_ref copy); +napi_status GetRefByCallback(napi_env env, std::list callbackList, napi_value callback, + napi_ref &callbackRef); +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif diff --git a/interfaces/kits/js/include/napi_errors.h b/interfaces/kits/js/include/napi_errors.h new file mode 100644 index 0000000..0d755c9 --- /dev/null +++ b/interfaces/kits/js/include/napi_errors.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi errors for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#ifndef NAPI_ERRORS_H +#define NAPI_ERRORS_H + +#include +#include "cast_engine_errors.h" + +namespace OHOS { +namespace CastEngine { +namespace NapiErrors { +static std::map errcode_ = { + { CAST_ENGINE_ERROR, CAST_ENGINE_ERROR }, + { ERR_NO_MEMORY, ERR_NO_MEMORY }, + { ERR_SESSION_NOT_EXIST, ERR_SESSION_NOT_EXIST }, + { ERR_SERVICE_STATE_NOT_MATCH, ERR_SERVICE_STATE_NOT_MATCH }, + { ERR_SESSION_STATE_NOT_MATCH, ERR_SESSION_STATE_NOT_MATCH }, + { ERR_NO_PERMISSION, ERR_NO_PERMISSION }, + { ERR_INVALID_PARAM, ERR_INVALID_PARAM } +}; +} +} // namespace CastEngine +} // namespace OHOS + +#endif // CAST_ENGINE_ERRORS_H \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_mirror_player.h b/interfaces/kits/js/include/napi_mirror_player.h new file mode 100644 index 0000000..43a431f --- /dev/null +++ b/interfaces/kits/js/include/napi_mirror_player.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface for cast mirror player. + * Author: zhangjingnan + * Create: 2023-5-27 + */ + +#ifndef NAPI_CAST_MIRROR_PLAYER_H_ +#define NAPI_CAST_MIRROR_PLAYER_H_ + +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "napi_errors.h" +#include "cast_engine_errors.h" +#include "i_mirror_player.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class NapiMirrorPlayer { +public: + static void DefineMirrorPlayerJSClass(napi_env env); + static napi_status CreateNapiMirrorPlayer(napi_env env, std::shared_ptr mirrorPlayer, + napi_value &out); + + NapiMirrorPlayer(std::shared_ptr mirrorPlayer) : mirrorPlayer_(mirrorPlayer) {} + NapiMirrorPlayer() = default; + ~NapiMirrorPlayer() = default; + std::shared_ptr GetMirrorPlayer() + { + std::lock_guard lock(mutex_); + return mirrorPlayer_; + } + void Reset() + { + std::lock_guard lock(mutex_); + mirrorPlayer_.reset(); + } + +private: + static napi_value NapiMirrorPlayerConstructor(napi_env env, napi_callback_info info); + static napi_value Play(napi_env env, napi_callback_info info); + static napi_value Pause(napi_env env, napi_callback_info info); + static napi_value SetSurface(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + std::mutex mutex_; + std::shared_ptr mirrorPlayer_; + static thread_local napi_ref consRef_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_stream_player.h b/interfaces/kits/js/include/napi_stream_player.h new file mode 100644 index 0000000..f6dcbb8 --- /dev/null +++ b/interfaces/kits/js/include/napi_stream_player.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface for stream player. + * Author: huangchanggui + * Create: 2023-1-11 + */ + +#ifndef NAPI_STREAM_PLAYER_H +#define NAPI_STREAM_PLAYER_H + +#include +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "i_stream_player.h" +#include "napi_stream_player_listener.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class EXPORT NapiStreamPlayer { +public: + using OnEventHandlerType = std::function; + using OffEventHandlerType = std::function; + + static void DefineStreamPlayerJSClass(napi_env env); + static napi_status CreateNapiStreamPlayer(napi_env env, std::shared_ptr player, napi_value &out); + std::shared_ptr NapiListenerGetter(); + void NapiListenerSetter(std::shared_ptr listener); + + explicit NapiStreamPlayer(std::shared_ptr player) : streamPlayer_(player) {} + NapiStreamPlayer() = default; + ~NapiStreamPlayer() = default; + std::shared_ptr GetStreamPlayer() + { + std::lock_guard lock(mutex_); + return streamPlayer_; + } + void Reset() + { + std::lock_guard lock(mutex_); + streamPlayer_.reset(); + listener_.reset(); + } + +private: + static napi_value NapiStreamPlayerConstructor(napi_env env, napi_callback_info info); + static napi_value SetSurface(napi_env env, napi_callback_info info); + static napi_value Load(napi_env env, napi_callback_info info); + static napi_value Start(napi_env env, napi_callback_info info); + static napi_value Play(napi_env env, napi_callback_info info); + static napi_value Pause(napi_env env, napi_callback_info info); + static napi_value Stop(napi_env env, napi_callback_info info); + static napi_value Next(napi_env env, napi_callback_info info); + static napi_value Previous(napi_env env, napi_callback_info info); + static napi_value Seek(napi_env env, napi_callback_info info); + static napi_value FastForward(napi_env env, napi_callback_info info); + static napi_value FastRewind(napi_env env, napi_callback_info info); + static napi_value SetVolume(napi_env env, napi_callback_info info); + static napi_value SetLoopMode(napi_env env, napi_callback_info info); + static napi_value SetSpeed(napi_env env, napi_callback_info info); + static napi_value GetPlayerStatus(napi_env env, napi_callback_info info); + static napi_value GetPosition(napi_env env, napi_callback_info info); + static napi_value GetVolume(napi_env env, napi_callback_info info); + static napi_value GetLoopMode(napi_env env, napi_callback_info info); + static napi_value GetPlaySpeed(napi_env env, napi_callback_info info); + static napi_value GetMediaInfoHolder(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + static napi_value OnEvent(napi_env env, napi_callback_info info); + static napi_value OffEvent(napi_env env, napi_callback_info info); + + static napi_status OnStateChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnPositionChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnMediaItemChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnVolumeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnVideoSizeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnLoopModeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnPlaySpeedChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnPlayerError(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnNextRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnPreviousRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnSeekDone(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OnEndOfStream(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + + static napi_status OffStateChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffPositionChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffMediaItemChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffVolumeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffVideoSizeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffLoopModeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffPlaySpeedChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffPlayerError(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffNextRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffPreviousRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffSeekDone(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + static napi_status OffEndOfStream(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer); + + static NapiStreamPlayer *GetNapiStreamPlayer(napi_env env, napi_callback_info info); + static napi_status RegisterNativeStreamPlayerListener(NapiStreamPlayer *napiStreamPlayer); + + static std::map> eventHandlers_; + std::mutex mutex_; + std::shared_ptr streamPlayer_; + std::shared_ptr listener_; + static thread_local napi_ref consRef_; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/include/napi_stream_player_listener.h b/interfaces/kits/js/include/napi_stream_player_listener.h new file mode 100644 index 0000000..ccadd1a --- /dev/null +++ b/interfaces/kits/js/include/napi_stream_player_listener.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player listener for napi interface. + * Author: huangchanggui + * Create: 2023-1-11 + */ + +#ifndef NAPI_STREAM_PLAYER_LISTENER_H +#define NAPI_STREAM_PLAYER_LISTENER_H + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_common.h" +#include "napi_callback.h" +#include "napi_castengine_utils.h" +#include "i_stream_player.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +class NapiStreamPlayerListener : public IStreamPlayerListener { +public: + using NapiArgsGetter = std::function; + enum { + EVENT_PLAYER_STATUS_CHANGED, + EVENT_POSITION_CHANGED, + EVENT_MEDIA_ITEM_CHANGED, + EVENT_VOLUME_CHANGED, + EVENT_VIDEO_SIZE_CHANGED, + EVENT_LOOP_MODE_CHANGED, + EVENT_PLAY_SPEED_CHANGED, + EVENT_PLAYER_ERROR, + EVENT_NEXT_REQUEST, + EVENT_PREVIOUS_REQUEST, + EVENT_SEEK_DONE, + EVENT_END_OF_STREAM, + EVENT_PLAY_REQUEST, + EVENT_TYPE_MAX + }; + + NapiStreamPlayerListener() {}; + ~NapiStreamPlayerListener() override; + + void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) override; + void OnPositionChanged(int position, int bufferPosition, int duration) override; + void OnMediaItemChanged(const MediaInfo &mediaInfo) override; + void OnVolumeChanged(int volume, int maxVolume) override; + void OnVideoSizeChanged(int width, int height) override; + void OnLoopModeChanged(const LoopMode loopMode) override; + void OnPlaySpeedChanged(const PlaybackSpeed speed) override; + void OnPlayerError(int errorCode, const std::string &errorMsg) override; + void OnNextRequest() override; + void OnPreviousRequest() override; + void OnSeekDone(int position) override; + void OnEndOfStream(int isLooping) override; + void OnPlayRequest(const MediaInfo &mediaInfo) override; + + napi_status AddCallback(napi_env env, int32_t event, napi_value callback); + napi_status RemoveCallback(napi_env env, int32_t event, napi_value callback); + +private: + void HandleEvent(int32_t event, NapiArgsGetter getter); + napi_status ClearCallback(napi_env env); + + std::mutex lock_; + std::shared_ptr callback_; + std::list callbacks_[EVENT_TYPE_MAX] {}; +}; +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_async_work.cpp b/interfaces/kits/js/src/napi_async_work.cpp new file mode 100644 index 0000000..224333d --- /dev/null +++ b/interfaces/kits/js/src/napi_async_work.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi async work realization for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#include "napi_async_work.h" +#include "napi_castengine_utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-AsyncWork"); + +NapiAsyncTask::~NapiAsyncTask() +{ + CLOGD("no memory leak after callback or promise[resolved/rejected]"); + if (env != nullptr) { + if (work != nullptr) { + NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, work)); + } + if (callbackRef != nullptr) { + NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, callbackRef)); + } + env = nullptr; + } +} + +void NapiAsyncTask::GetJSInfo(napi_env envi, napi_callback_info info, NapiCbInfoParser parser, bool sync) +{ + env = envi; + size_t argc = ARGC_MAX; + napi_value argv[ARGC_MAX] = {nullptr}; + napi_value thisVar = nullptr; + status = napi_get_cb_info(envi, info, &argc, argv, &thisVar, nullptr); + if (status != napi_ok || argc > ARGC_MAX) { + CLOGE("napi_get_cb_info failed"); + return; + } + status = napi_unwrap(envi, thisVar, &native); + if (status != napi_ok) { + CLOGE("napi_unwrap failed"); + return; + } + if (native == nullptr) { + CLOGD("thisVar is null"); + } + + if (!sync && argc > 0) { + // get the last arguments :: + size_t index = argc - 1; + napi_valuetype type = napi_undefined; + status = napi_typeof(envi, argv[index], &type); + if ((status == napi_ok) && (type == napi_function)) { + status = napi_create_reference(envi, argv[index], 1, &callbackRef); + if (status != napi_ok) { + CLOGE("napi_get_cb_info failed"); + return; + } + argc = index; + CLOGD("async callback, no promise"); + } else { + CLOGD("no callback, async promise"); + } + } + + if (parser) { + CLOGD("input parser exists"); + parser(argc, argv); + } +} + +napi_value NapiAsyncWork::Enqueue(napi_env env, std::shared_ptr napiAsyncTask, const std::string &name, + NapiAsyncExecute execute, NapiAsyncComplete complete) +{ + CLOGI("name=%{public}s", name.c_str()); + napiAsyncTask->execute = std::move(execute); + napiAsyncTask->complete = std::move(complete); + napiAsyncTask->taskName = name; + napi_value promise = nullptr; + if (napiAsyncTask->callbackRef == nullptr) { + NAPI_CALL(napiAsyncTask->env, napi_create_promise(napiAsyncTask->env, &napiAsyncTask->deferred, &promise)); + CLOGD("create deferred promise"); + } else { + NAPI_CALL(napiAsyncTask->env, napi_get_undefined(napiAsyncTask->env, &promise)); + } + + napi_value resourceName = nullptr; + NAPI_CALL(napiAsyncTask->env, + napi_create_string_utf8(napiAsyncTask->env, name.c_str(), NAPI_AUTO_LENGTH, &resourceName)); + napi_create_async_work( + napiAsyncTask->env, nullptr, resourceName, + [](napi_env env, void *data) { + if (data == nullptr) { + CLOGE("napi_async_execute_callback nullptr"); + return; + } + auto task = reinterpret_cast(data); + CLOGD("napi_async_execute_callback status=%{public}d", task->status); + if (task->execute && task->status == napi_ok) { + task->execute(); + task->execute = nullptr; + } + }, + [](napi_env env, napi_status status, void *data) { + if (data == nullptr) { + CLOGE("napi_async_complete_callback nullptr"); + return; + } + auto task = reinterpret_cast(data); + CLOGD("napi_async_complete_callback status=%{public}d, status=%{public}d", status, task->status); + if ((status != napi_ok) && (task->status == napi_ok)) { + task->status = status; + } + if ((task->complete) && (status == napi_ok) && (task->status == napi_ok)) { + task->complete(task->output); + task->complete = nullptr; + } + GenerateOutput(task); + }, + reinterpret_cast(napiAsyncTask.get()), &napiAsyncTask->work); + NAPI_CALL(napiAsyncTask->env, napi_queue_async_work(napiAsyncTask->env, napiAsyncTask->work)); + napiAsyncTask->hold = napiAsyncTask; // save crossing-thread ctxt. + return promise; +} + +void NapiAsyncWork::GenerateOutput(NapiAsyncTask *napiAsyncTask) +{ + napi_value result[RESULT_ALL] = {nullptr}; + if (napiAsyncTask->status == napi_ok) { + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, napi_get_undefined(napiAsyncTask->env, &result[RESULT_ERROR])); + if (napiAsyncTask->output == nullptr) { + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, napi_get_undefined(napiAsyncTask->env, &napiAsyncTask->output)); + } + result[RESULT_DATA] = napiAsyncTask->output; + } else { + napi_value message = nullptr; + napi_value code = nullptr; + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, + napi_create_string_utf8(napiAsyncTask->env, napiAsyncTask->errMessage.c_str(), NAPI_AUTO_LENGTH, &message)); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, + napi_create_error(napiAsyncTask->env, nullptr, message, &result[RESULT_ERROR])); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, napi_create_int32(napiAsyncTask->env, napiAsyncTask->errCode, &code)); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, + napi_set_named_property(napiAsyncTask->env, result[RESULT_ERROR], "code", code)); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, napi_get_undefined(napiAsyncTask->env, &result[RESULT_DATA])); + } + + if (napiAsyncTask->deferred != nullptr) { + if (napiAsyncTask->status == napi_ok) { + CLOGD("deferred promise resolved"); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, + napi_resolve_deferred(napiAsyncTask->env, napiAsyncTask->deferred, result[RESULT_DATA])); + } else { + CLOGD("deferred promise rejected"); + NAPI_CALL_RETURN_VOID(napiAsyncTask->env, + napi_reject_deferred(napiAsyncTask->env, napiAsyncTask->deferred, result[RESULT_ERROR])); + } + } else { + CallJSFunc(napiAsyncTask->env, napiAsyncTask->callbackRef, RESULT_ALL, result); + } + napiAsyncTask->hold.reset(); // release napiAsyncTask. +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_callback.cpp b/interfaces/kits/js/src/napi_callback.cpp new file mode 100644 index 0000000..a1c9a8a --- /dev/null +++ b/interfaces/kits/js/src/napi_callback.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi callback realization for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#include +#include "cast_engine_log.h" +#include "napi_callback.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-Callback"); + +NapiCallback::NapiCallback(napi_env env) : env_(env) +{ + if (env != nullptr) { + NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop_)); + } +} + +NapiCallback::~NapiCallback() +{ + CLOGD("no memory leak for queue-callback"); + env_ = nullptr; +} + +napi_env NapiCallback::GetEnv() const +{ + return env_; +} + +void NapiCallback::AfterWorkCallback(uv_work_t *work, int status) +{ + std::shared_ptr context(static_cast(work->data), [work](DataContext *ptr) { + delete ptr; + delete work; + }); + + int argc = 0; + napi_handle_scope scope = nullptr; + napi_open_handle_scope(context->env, &scope); + napi_value argv[ARGC_MAX] = { nullptr }; + if (context->getter) { + argc = ARGC_MAX; + context->getter(context->env, argc, argv); + } + + napi_value undefined = nullptr; + if (napi_get_undefined(context->env, &undefined) != napi_ok) { + CLOGE("napi_get_undefined failed"); + napi_close_handle_scope(context->env, scope); + return; + } + napi_value callback = nullptr; + if (napi_get_reference_value(context->env, context->method, &callback) != napi_ok) { + CLOGE("napi_get_reference_value failed"); + napi_close_handle_scope(context->env, scope); + return; + } + napi_value callResult = nullptr; + if (napi_call_function(context->env, undefined, callback, argc, argv, &callResult) != napi_ok) { + CLOGE("napi_call_function failed"); + } + napi_close_handle_scope(context->env, scope); +} + +void NapiCallback::Call(napi_ref method, NapiArgsGetter getter) +{ + CLOGD("Start to have JS call"); + if (loop_ == nullptr) { + CLOGE("loop_ is nullptr"); + return; + } + if (method == nullptr) { + CLOGE("method is nullptr"); + return; + } + + auto *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + CLOGE("no memory for uv_work_t"); + return; + } + + work->data = new DataContext { env_, method, std::move(getter) }; + int res = uv_queue_work( + loop_, work, [](uv_work_t *work) {}, AfterWorkCallback); + if (res != 0) { + CLOGE("uv queue work failed"); + delete work; + return; + } +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_cast_session.cpp b/interfaces/kits/js/src/napi_cast_session.cpp new file mode 100644 index 0000000..e73e0a1 --- /dev/null +++ b/interfaces/kits/js/src/napi_cast_session.cpp @@ -0,0 +1,663 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface realization for cast session. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "oh_remote_control_event.h" +#include "i_cast_session.h" +#include "cast_session_manager.h" +#include "napi_castengine_utils.h" +#include "napi_cast_session_listener.h" +#include "napi_cast_session.h" +#include "napi_stream_player.h" +#include "napi_mirror_player.h" +#include "napi_async_work.h" + +using namespace OHOS::CastEngine::CastEngineClient; +using namespace std; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-Session"); + +thread_local napi_ref NapiCastSession::consRef_ = nullptr; + +std::map> + NapiCastSession::eventHandlers_ = { + { "event", { OnInnerEvent, OffInnerEvent } }, + { "deviceState", { OnDeviceState, OffDeviceState } } +}; + +void NapiCastSession::DefineCastSessionJSClass(napi_env env) +{ + napi_property_descriptor NapiCastSessionDesc[] = { + DECLARE_NAPI_FUNCTION("on", OnEvent), + DECLARE_NAPI_FUNCTION("off", OffEvent), + DECLARE_NAPI_FUNCTION("addDevice", AddDevice), + DECLARE_NAPI_FUNCTION("removeDevice", RemoveDevice), + DECLARE_NAPI_FUNCTION("getSessionId", GetSessionId), + DECLARE_NAPI_FUNCTION("setSessionProperty", SetSessionProperty), + DECLARE_NAPI_FUNCTION("createMirrorPlayer", CreateMirrorPlayer), + DECLARE_NAPI_FUNCTION("createStreamPlayer", CreateStreamPlayer), + DECLARE_NAPI_FUNCTION("setCastMode", SetCastMode), + DECLARE_NAPI_FUNCTION("release", Release) + }; + + napi_value castSession = nullptr; + constexpr int initialRefCount = 1; + napi_status status = napi_define_class(env, "castSession", NAPI_AUTO_LENGTH, NapiCastSessionConstructor, nullptr, + sizeof(NapiCastSessionDesc) / sizeof(NapiCastSessionDesc[0]), NapiCastSessionDesc, &castSession); + if (status != napi_ok) { + CLOGE("napi_define_class failed"); + return; + } + status = napi_create_reference(env, castSession, initialRefCount, &consRef_); + if (status != napi_ok) { + CLOGE("DefineCastSessionJSClass napi_create_reference failed"); + } +} + +napi_value NapiCastSession::NapiCastSessionConstructor(napi_env env, napi_callback_info info) +{ + CLOGD("NapiCastSession start to construct in"); + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); + CLOGD("NapiCastSession construct successfully"); + return thisVar; +} + +napi_status NapiCastSession::CreateNapiCastSession(napi_env env, shared_ptr session, napi_value &out) +{ + CLOGD("Start to create napiCastSession in"); + napi_value result = nullptr; + napi_value constructor = nullptr; + if (consRef_ == nullptr || session == nullptr) { + CLOGE("CreateNapiCastSession input is null"); + return napi_generic_failure; + } + napi_status status = napi_get_reference_value(env, consRef_, &constructor); + if (status != napi_ok || constructor == nullptr) { + CLOGE("CreateNapiCastSession napi_get_reference_value failed"); + return napi_generic_failure; + } + + constexpr size_t argc = 0; + status = napi_new_instance(env, constructor, argc, nullptr, &result); + if (status != napi_ok) { + CLOGE("CreateNapiCastSession napi_new_instance failed"); + return napi_generic_failure; + } + + NapiCastSession *napiCastSession = new NapiCastSession(session); + if (napiCastSession == nullptr) { + CLOGE("NapiCastSession is nullptr"); + return napi_generic_failure; + } + auto finalize = [](napi_env env, void *data, void *hint) { + NapiCastSession *session = reinterpret_cast(data); + if (session != nullptr) { + CLOGI("Session deconstructed"); + delete session; + session = nullptr; + } + }; + if (napi_wrap(env, result, napiCastSession, finalize, nullptr, nullptr) != napi_ok) { + CLOGE("CreateNapiCastSession napi_wrap failed"); + delete napiCastSession; + napiCastSession = nullptr; + return napi_generic_failure; + } + out = result; + CLOGD("Create napiCastSession successfully"); + return napi_ok; +} + +NapiCastSession *NapiCastSession::GetNapiCastSession(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + NAPI_CALL_BASE(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), nullptr); + + NapiCastSession *napiCastSession = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, thisVar, reinterpret_cast(&napiCastSession)), nullptr); + if (napiCastSession == nullptr) { + CLOGE("napi_unwrap napiStreamPlayer is null"); + return nullptr; + } + + return napiCastSession; +} + +napi_value NapiCastSession::OnEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function }; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + std::string eventName = ParseString(env, argv[0]); + NapiCastSession *napiSession = GetNapiCastSession(env, info); + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return GetUndefinedValue(env); + } + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + + if (RegisterNativeSessionListener(napiSession) == napi_generic_failure) { + return GetUndefinedValue(env); + } + if (it->second.first(env, argv[1], napiSession) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_value NapiCastSession::OffEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function}; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + + std::string eventName = ParseString(env, argv[0]); + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + NapiCastSession *napiSession = GetNapiCastSession(env, info); + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return GetUndefinedValue(env); + } + if (it->second.second(env, argv[1], napiSession) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_status NapiCastSession::RegisterNativeSessionListener(NapiCastSession *napiSession) +{ + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return napi_generic_failure; + } + if (napiSession->NapiListenerGetter()) { + return napi_ok; + } + auto session = napiSession->GetCastSession(); + if (!session) { + CLOGE("Session is null"); + return napi_generic_failure; + } + + auto listener = std::make_shared(); + if (!listener) { + CLOGE("Failed to malloc session listener"); + return napi_generic_failure; + } + int32_t ret = session->RegisterListener(listener); + if (ret != CAST_ENGINE_SUCCESS) { + CLOGE("native register session listener failed"); + return napi_generic_failure; + } + napiSession->NapiListenerSetter(listener); + + return napi_ok; +} + +napi_status NapiCastSession::OnInnerEvent(napi_env env, napi_value callback, NapiCastSession *napiSession) +{ + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return napi_generic_failure; + } + if (!napiSession->NapiListenerGetter()) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (napiSession->NapiListenerGetter()->AddCallback(env, NapiCastSessionListener::EVENT_ON_EVENT, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSession::OnDeviceState(napi_env env, napi_value callback, NapiCastSession *napiSession) +{ + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return napi_generic_failure; + } + if (!napiSession->NapiListenerGetter()) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (napiSession->NapiListenerGetter()->AddCallback(env, NapiCastSessionListener::EVENT_DEVICE_STATE, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSession::OffInnerEvent(napi_env env, napi_value callback, NapiCastSession *napiSession) +{ + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return napi_generic_failure; + } + if (!napiSession->NapiListenerGetter()) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (napiSession->NapiListenerGetter()->RemoveCallback(env, NapiCastSessionListener::EVENT_ON_EVENT, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSession::OffDeviceState(napi_env env, napi_value callback, NapiCastSession *napiSession) +{ + if (napiSession == nullptr) { + CLOGE("napiSession is null"); + return napi_generic_failure; + } + if (!napiSession->NapiListenerGetter()) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (napiSession->NapiListenerGetter()->RemoveCallback(env, NapiCastSessionListener::EVENT_DEVICE_STATE, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_value NapiCastSession::AddDevice(napi_env env, napi_callback_info info) +{ + CLOGD("Start to add device in"); + struct ConcreteTask : public NapiAsyncTask { + CastRemoteDevice castRemoteDevice_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->castRemoteDevice_ = GetCastRemoteDeviceFromJS(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->AddDevice(napiAsyntask->castRemoteDevice_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "AddDevice failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "AddDevice failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "AddDevice failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "AddDevice", executor, complete); +} + +napi_value NapiCastSession::RemoveDevice(napi_env env, napi_callback_info info) +{ + CLOGD("Start to remove device in"); + struct ConcreteTask : public NapiAsyncTask { + string deviceId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->deviceId_ = ParseString(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->RemoveDevice(napiAsyntask->deviceId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "RemoveDevice failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "RemoveDevice failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "RemoveDevice failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "RemoveDevice", executor, complete); +} + +napi_value NapiCastSession::GetSessionId(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get sessionId in"); + struct ConcreteTask : public NapiAsyncTask { + string sessionId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->GetSessionId(napiAsyntask->sessionId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetSessionId failed : no permission"; + } else { + napiAsyntask->errMessage = "GetSessionId failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = + napi_create_string_utf8(env, napiAsyntask->sessionId_.c_str(), NAPI_AUTO_LENGTH, &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_string_utf8 failed", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetSessionId", executor, complete); +} + +napi_value NapiCastSession::SetSessionProperty(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set sessionProperty in"); + struct ConcreteTask : public NapiAsyncTask { + CastSessionProperty castSessionProperty_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->castSessionProperty_ = GetCastSessionPropertyFromJS(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->SetSessionProperty(napiAsyntask->castSessionProperty_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetSessionProperty failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetSessionProperty failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetSessionProperty failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetSessionProperty", executor, complete); +} + +napi_value NapiCastSession::CreateMirrorPlayer(napi_env env, napi_callback_info info) +{ + CLOGD("Start to create mirror Player"); + struct ConcreteTask : public NapiAsyncTask { + shared_ptr player_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->CreateMirrorPlayer(napiAsyntask->player_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "CreateMirrorPlayer failed : no permission"; + } else { + napiAsyntask->errMessage = "CreateMirrorPlayer failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [napiAsyntask](napi_value &output) { + napiAsyntask->status = + NapiMirrorPlayer::CreateNapiMirrorPlayer(napiAsyntask->env, napiAsyntask->player_, output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "convert native object to javascript object failed", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "CreateMirrorPlayer", executor, complete); +} + +napi_value NapiCastSession::CreateStreamPlayer(napi_env env, napi_callback_info info) +{ + CLOGD("Start to create Stream Player"); + struct ConcreteTask : public NapiAsyncTask { + shared_ptr player_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->CreateStreamPlayer(napiAsyntask->player_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "CreateStreamPlayer failed : no permission"; + } else { + napiAsyntask->errMessage = "CreateStreamPlayer failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [napiAsyntask](napi_value &output) { + napiAsyntask->status = + NapiStreamPlayer::CreateNapiStreamPlayer(napiAsyntask->env, napiAsyntask->player_, output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "convert native object to javascript object failed", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "CreateStreamPlayer", executor, complete); +} + +napi_value NapiCastSession::SetCastMode(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set cast mode in"); + struct ConcreteTask : public NapiAsyncTask { + CastMode castMode_; + string jsonParam_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 2; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number, napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->castMode_ = static_cast(ParseInt32(env, argv[0])); + napiAsyntask->jsonParam_ = ParseString(env, argv[1]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->SetCastMode(napiAsyntask->castMode_, napiAsyntask->jsonParam_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetCastMode failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetCastMode failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetCastMode failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetCastMode", executor, complete); +} + +napi_value NapiCastSession::Release(napi_env env, napi_callback_info info) +{ + CLOGD("Start to release in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + napiAsyntask->GetJSInfo(env, info); + + auto executor = [napiAsyntask]() { + auto *napiSession = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiSession != nullptr, "napiSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr castSession = napiSession->GetCastSession(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, castSession, "ICastSession is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = castSession->Release(); + if (ret == CAST_ENGINE_SUCCESS) { + napiSession->Reset(); + } else if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Release failed : no permission"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } else { + napiAsyntask->errMessage = "Release failed : native server exception"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete); +} + +std::shared_ptr NapiCastSession::NapiListenerGetter() +{ + return listener_; +} + +void NapiCastSession::NapiListenerSetter(std::shared_ptr listener) +{ + listener_ = listener; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_cast_session_listener.cpp b/interfaces/kits/js/src/napi_cast_session_listener.cpp new file mode 100644 index 0000000..a476410 --- /dev/null +++ b/interfaces/kits/js/src/napi_cast_session_listener.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session listener realization for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_castengine_utils.h" +#include "napi_cast_session_listener.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-SessionListener"); + +NapiCastSessionListener::~NapiCastSessionListener() +{ + CLOGD("destrcutor in"); + ClearCallback(callback_->GetEnv()); +} + +void NapiCastSessionListener::HandleEvent(int32_t event, NapiArgsGetter getter) +{ + std::lock_guard lockGuard(lock_); + if (callbacks_[event].empty()) { + CLOGE("not register callback event=%{public}d", event); + return; + } + for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) { + callback_->Call(*ref, getter); + } +} + +void NapiCastSessionListener::OnDeviceState(const DeviceStateInfo &stateEvent) +{ + CLOGD("OnDeviceState start"); + NapiArgsGetter napiArgsGetter = [stateEvent](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + argv[0] = ConvertDeviceStateInfoToJS(env, stateEvent); + }; + HandleEvent(EVENT_DEVICE_STATE, napiArgsGetter); + CLOGD("OnDeviceState finish"); +} + +void NapiCastSessionListener::OnEvent(const EventId &eventId, const std::string &jsonParam) +{ + CLOGD("OnEvent start"); + NapiArgsGetter napiArgsGetter = [eventId, jsonParam](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_TWO; + auto status = napi_create_int32(env, static_cast(eventId), &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_string_utf8(env, jsonParam.c_str(), NAPI_AUTO_LENGTH, &argv[1]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_string_utf8 failed"); + }; + HandleEvent(EVENT_ON_EVENT, napiArgsGetter); + CLOGD("OnEvent finish"); +} + +napi_status NapiCastSessionListener::AddCallback(napi_env env, int32_t event, napi_value callback) +{ + CLOGI("Add callback %{public}d", event); + constexpr int initialRefCount = 1; + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been registered"); + return napi_ok; + } + napi_status status = napi_create_reference(env, callback, initialRefCount, &ref); + if (status != napi_ok) { + CLOGE("napi_create_reference failed"); + return status; + } + if (callback_ == nullptr) { + callback_ = std::make_shared(env); + if (callback_ == nullptr) { + CLOGE("no memory"); + return napi_generic_failure; + } + } + callbacks_[event].push_back(ref); + return napi_ok; +} + +napi_status NapiCastSessionListener::RemoveCallback(napi_env env, int32_t event, napi_value callback) +{ + if (callback == nullptr) { + for (auto &callbackRef : callbacks_[event]) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callbacks_[event].clear(); + return napi_ok; + } + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been remove"); + return napi_ok; + } + callbacks_[event].remove(ref); + return napi_delete_reference(env, ref); +} + +napi_status NapiCastSessionListener::ClearCallback(napi_env env) +{ + for (auto &callback : callbacks_) { + for (auto &callbackRef : callback) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callback.clear(); + } + + return napi_ok; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/interfaces/kits/js/src/napi_cast_session_manager.cpp b/interfaces/kits/js/src/napi_cast_session_manager.cpp new file mode 100644 index 0000000..83f82b2 --- /dev/null +++ b/interfaces/kits/js/src/napi_cast_session_manager.cpp @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface realization for cast session manager. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "cast_session_manager.h" +#include "napi_cast_session_manager_listener.h" +#include "napi_cast_session.h" +#include "napi_castengine_utils.h" +#include "napi_cast_session_manager.h" +#include "napi_async_work.h" + +using namespace OHOS::CastEngine::CastEngineClient; +using namespace std; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-SessionManager"); + +std::shared_ptr NapiCastSessionManager::listener_; + +std::map> + NapiCastSessionManager::eventHandlers_ = { + { "serviceDie", { OnServiceDied, OffServiceDie } }, + { "deviceFound", { OnDeviceFound, OffDeviceFound } }, + { "sessionCreate", { OnSessionCreated, OffSessionCreated } } +}; + +napi_value NapiCastSessionManager::Init(napi_env env, napi_value exports) +{ + napi_property_descriptor NapiCastSessionManagerDesc[] = { + DECLARE_NAPI_FUNCTION("on", OnEvent), + DECLARE_NAPI_FUNCTION("off", OffEvent), + DECLARE_NAPI_FUNCTION("startDiscovery", StartDiscovery), + DECLARE_NAPI_FUNCTION("stopDiscovery", StopDiscovery), + DECLARE_NAPI_FUNCTION("setDiscoverable", SetDiscoverable), + DECLARE_NAPI_FUNCTION("createCastSession", CreateCastSession), + DECLARE_NAPI_FUNCTION("release", Release) + }; + + napi_status status = napi_define_properties(env, exports, + sizeof(NapiCastSessionManagerDesc) / sizeof(napi_property_descriptor), NapiCastSessionManagerDesc); + if (status != napi_ok) { + CLOGE("define manager properties failed"); + return GetUndefinedValue(env); + } + return exports; +} + +napi_value NapiCastSessionManager::StartDiscovery(napi_env env, napi_callback_info info) +{ + CLOGD("Start to discovery in"); + struct ConcreteTask : public NapiAsyncTask { + int protocolType_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + int32_t protocolTypeInt; + bool isProtocolTypesValid = GetProtocolTypesFromJS(env, argv[0], protocolTypeInt); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isProtocolTypesValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->protocolType_ = protocolTypeInt; + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + int32_t ret = CastSessionManager::GetInstance().StartDiscovery(napiAsyntask->protocolType_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "StartDiscovery failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "StartDiscovery failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "StartDiscovery failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "StartDiscovery", executor, complete); +} + +napi_value NapiCastSessionManager::StopDiscovery(napi_env env, napi_callback_info info) +{ + CLOGD("Start to stop discovery in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + napiAsyntask->GetJSInfo(env, info); + + auto executor = [napiAsyntask]() { + int32_t ret = CastSessionManager::GetInstance().StopDiscovery(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "StopDiscovery failed : no permission"; + } else { + napiAsyntask->errMessage = "StopDiscovery failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "StopDiscovery", executor, complete); +} + +napi_value NapiCastSessionManager::SetDiscoverable(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set discoverable in"); + struct ConcreteTask : public NapiAsyncTask { + bool isEnable_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_boolean }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->isEnable_ = ParseBool(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + int32_t ret = CastSessionManager::GetInstance().SetDiscoverable(napiAsyntask->isEnable_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetDiscoverable failed : no permission"; + } else { + napiAsyntask->errMessage = "SetDiscoverable failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetDiscoverable", executor, complete); +} + +napi_value NapiCastSessionManager::CreateCastSession(napi_env env, napi_callback_info info) +{ + CLOGD("Start to create castSession in"); + struct ConcreteTask : public NapiAsyncTask { + CastSessionProperty property_; + std::shared_ptr session_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->property_ = GetCastSessionPropertyFromJS(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + int32_t ret = + CastSessionManager::GetInstance().CreateCastSession(napiAsyntask->property_, napiAsyntask->session_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "CreateCastSession failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "CreateCastSession failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "CreateCastSession failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [napiAsyntask](napi_value &output) { + napiAsyntask->status = + NapiCastSession::CreateNapiCastSession(napiAsyntask->env, napiAsyntask->session_, output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "convert native object to javascript object failed", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "CreateCastSession", executor, complete); +} + +napi_value NapiCastSessionManager::Release(napi_env env, napi_callback_info info) +{ + CLOGD("Start to release in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + napiAsyntask->GetJSInfo(env, info); + + auto executor = [napiAsyntask]() { + int32_t ret = CastSessionManager::GetInstance().Release(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Release failed : no permission"; + } else { + napiAsyntask->errMessage = "Release failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete); +} + +napi_value NapiCastSessionManager::OnEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function }; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + + std::string eventName = ParseString(env, argv[0]); + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + + if (RegisterNativeSessionManagerListener() == napi_generic_failure) { + return GetUndefinedValue(env); + } + if (it->second.first(env, argv[1]) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_value NapiCastSessionManager::OffEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function}; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + + std::string eventName = ParseString(env, argv[0]); + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + if (it->second.second(env, argv[1]) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_status NapiCastSessionManager::OnServiceDied(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_SERVICE_DIED, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::OnDeviceFound(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_FOUND, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::OnSessionCreated(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->AddCallback(env, NapiCastSessionManagerListener::EVENT_SESSION_CREATE, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::OffServiceDie(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_SERVICE_DIED, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::OffDeviceFound(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_DEVICE_FOUND, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::OffSessionCreated(napi_env env, napi_value callback) +{ + if (!listener_) { + CLOGE("cast session manager callback is null"); + return napi_generic_failure; + } + if (listener_->RemoveCallback(env, NapiCastSessionManagerListener::EVENT_SESSION_CREATE, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiCastSessionManager::RegisterNativeSessionManagerListener() +{ + if (listener_) { + return napi_ok; + } + listener_ = std::make_shared(); + if (!listener_) { + CLOGE("Failed to malloc session manager listener"); + return napi_generic_failure; + } + int32_t ret = CastSessionManager::GetInstance().RegisterListener(listener_); + if (ret != CAST_ENGINE_SUCCESS) { + CLOGE("native register session manager listener failed"); + return napi_generic_failure; + } + + return napi_ok; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_cast_session_manager_listener.cpp b/interfaces/kits/js/src/napi_cast_session_manager_listener.cpp new file mode 100644 index 0000000..1027b89 --- /dev/null +++ b/interfaces/kits/js/src/napi_cast_session_manager_listener.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager listener realization for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "cast_session_manager.h" +#include "napi_cast_session.h" +#include "napi_castengine_utils.h" +#include "napi_cast_session_manager_listener.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-SessionManagerListener"); + +NapiCastSessionManagerListener::~NapiCastSessionManagerListener() +{ + CLOGD("destrcutor in"); + ClearCallback(callback_->GetEnv()); +} + +void NapiCastSessionManagerListener::HandleEvent(int32_t event, NapiArgsGetter getter) +{ + std::lock_guard lockGuard(lock_); + if (callbacks_[event].empty()) { + CLOGE("not register callback event=%{public}d", event); + return; + } + for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) { + callback_->Call(*ref, getter); + } +} + +void NapiCastSessionManagerListener::OnDeviceFound(const std::vector &deviceList) +{ + CLOGD("OnDeviceFound start"); + NapiArgsGetter napiArgsGetter = [deviceList](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + argv[0] = ConvertDeviceListToJS(env, deviceList); + }; + HandleEvent(EVENT_DEVICE_FOUND, napiArgsGetter); + CLOGD("OnDeviceFound finish"); +} + +void NapiCastSessionManagerListener::OnDeviceOffline(const std::string &deviceId) +{ + CLOGD("OnDeviceOffline start"); +} + +void NapiCastSessionManagerListener::OnSessionCreated(const std::shared_ptr &castSession) +{ + CLOGD("OnSessionCreated start"); + NapiArgsGetter napiArgsGetter = [castSession](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + argv[0] = ConvertCastSessionToJS(env, castSession); + }; + HandleEvent(EVENT_SESSION_CREATE, napiArgsGetter); + CLOGD("OnSessionCreated finish"); +} + +void NapiCastSessionManagerListener::OnServiceDied() +{ + CLOGD("OnServiceDied start"); + NapiArgsGetter napiArgsGetter = [](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ZERO; + argv[0] = { nullptr }; + }; + HandleEvent(EVENT_SERVICE_DIED, napiArgsGetter); + CLOGD("OnServiceDied finish"); +} + +napi_status NapiCastSessionManagerListener::AddCallback(napi_env env, int32_t event, napi_value callback) +{ + CLOGI("Add callback %{public}d", event); + constexpr int initialRefCount = 1; + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been registered"); + return napi_ok; + } + napi_status status = napi_create_reference(env, callback, initialRefCount, &ref); + if (status != napi_ok) { + CLOGE("napi_create_reference failed"); + return status; + } + if (callback_ == nullptr) { + callback_ = std::make_shared(env); + if (callback_ == nullptr) { + CLOGE("no memory"); + return napi_generic_failure; + } + } + callbacks_[event].push_back(ref); + return napi_ok; +} + +napi_status NapiCastSessionManagerListener::RemoveCallback(napi_env env, int32_t event, napi_value callback) +{ + if (callback == nullptr) { + for (auto &callbackRef : callbacks_[event]) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callbacks_[event].clear(); + return napi_ok; + } + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been remove"); + return napi_ok; + } + callbacks_[event].remove(ref); + return napi_delete_reference(env, ref); +} + +napi_status NapiCastSessionManagerListener::ClearCallback(napi_env env) +{ + for (auto &callback : callbacks_) { + for (auto &callbackRef : callback) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callback.clear(); + } + + return napi_ok; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_castengine_enum.cpp b/interfaces/kits/js/src/napi_castengine_enum.cpp new file mode 100644 index 0000000..6fb5ffe --- /dev/null +++ b/interfaces/kits/js/src/napi_castengine_enum.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi nums realization for interfaces. + * Author: zhangjingnan + * Create: 2023-4-11 + */ + +#include + +#include "napi/native_common.h" +#include "cast_engine_common.h" +#include "napi_castengine_enum.h" +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-Enum"); + +static napi_status SetNamedProperty(napi_env env, napi_value &obj, const std::string &name, int32_t value) +{ + napi_value property = nullptr; + napi_status status = napi_create_int32(env, value, &property); + if (status != napi_ok) { + CLOGE("napi_create_int32 failed"); + return status; + } + status = napi_set_named_property(env, obj, name.c_str(), property); + if (status != napi_ok) { + CLOGD("napi_set_named_property failed"); + return status; + } + return status; +} + +static napi_value ExportPlayerStates(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "PLAYER_STATE_ERROR", static_cast(PlayerStates::PLAYER_STATE_ERROR)); + (void)SetNamedProperty(env, result, "PLAYER_IDLE", static_cast(PlayerStates::PLAYER_IDLE)); + (void)SetNamedProperty(env, result, "PLAYER_INITIALIZED", static_cast(PlayerStates::PLAYER_INITIALIZED)); + (void)SetNamedProperty(env, result, "PLAYER_PREPARING", static_cast(PlayerStates::PLAYER_PREPARING)); + (void)SetNamedProperty(env, result, "PLAYER_PREPARED", static_cast(PlayerStates::PLAYER_PREPARED)); + (void)SetNamedProperty(env, result, "PLAYER_STARTED", static_cast(PlayerStates::PLAYER_STARTED)); + (void)SetNamedProperty(env, result, "PLAYER_PAUSED", static_cast(PlayerStates::PLAYER_PAUSED)); + (void)SetNamedProperty(env, result, "PLAYER_STOPPED", static_cast(PlayerStates::PLAYER_STOPPED)); + (void)SetNamedProperty(env, result, "PLAYER_PLAYBACK_COMPLETE", + static_cast(PlayerStates::PLAYER_PLAYBACK_COMPLETE)); + (void)SetNamedProperty(env, result, "PLAYER_RELEASED", static_cast(PlayerStates::PLAYER_RELEASED)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportPlaybackSpeed(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "SPEED_FORWARD_0_75_X", + static_cast(PlaybackSpeed::SPEED_FORWARD_0_75_X)); + (void)SetNamedProperty(env, result, "SPEED_FORWARD_1_00_X", + static_cast(PlaybackSpeed::SPEED_FORWARD_1_00_X)); + (void)SetNamedProperty(env, result, "SPEED_FORWARD_1_25_X", + static_cast(PlaybackSpeed::SPEED_FORWARD_1_25_X)); + (void)SetNamedProperty(env, result, "SPEED_FORWARD_1_75_X", + static_cast(PlaybackSpeed::SPEED_FORWARD_1_75_X)); + (void)SetNamedProperty(env, result, "SPEED_FORWARD_2_00_X", + static_cast(PlaybackSpeed::SPEED_FORWARD_2_00_X)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportLoopMode(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "LOOP_MODE_SEQUENCE", static_cast(LoopMode::LOOP_MODE_SEQUENCE)); + (void)SetNamedProperty(env, result, "LOOP_MODE_SINGLE", static_cast(LoopMode::LOOP_MODE_SINGLE)); + (void)SetNamedProperty(env, result, "LOOP_MODE_LIST", static_cast(LoopMode::LOOP_MODE_LIST)); + (void)SetNamedProperty(env, result, "LOOP_MODE_SHUFFLE", static_cast(LoopMode::LOOP_MODE_SHUFFLE)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportDeviceType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "DEVICE_OTHERS", static_cast(DeviceType::DEVICE_OTHERS)); + (void)SetNamedProperty(env, result, "DEVICE_SCREEN_PLAYER", static_cast(DeviceType::DEVICE_SCREEN_PLAYER)); + (void)SetNamedProperty(env, result, "DEVICE_HW_TV", static_cast(DeviceType::DEVICE_HW_TV)); + (void)SetNamedProperty(env, result, "DEVICE_SOUND_BOX", static_cast(DeviceType::DEVICE_SOUND_BOX)); + (void)SetNamedProperty(env, result, "DEVICE_HICAR", static_cast(DeviceType::DEVICE_HICAR)); + (void)SetNamedProperty(env, result, "DEVICE_MATEBOOK", static_cast(DeviceType::DEVICE_MATEBOOK)); + (void)SetNamedProperty(env, result, "DEVICE_PAD", static_cast(DeviceType::DEVICE_PAD)); + (void)SetNamedProperty(env, result, "DEVICE_CAST_PLUS", static_cast(DeviceType::DEVICE_CAST_PLUS)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportSubDeviceType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "SUB_DEVICE_DEFAULT", static_cast(SubDeviceType::SUB_DEVICE_DEFAULT)); + (void)SetNamedProperty(env, result, "SUB_DEVICE_MATEBOOK_PAD", + static_cast(SubDeviceType::SUB_DEVICE_MATEBOOK_PAD)); + (void)SetNamedProperty(env, result, "SUB_DEVICE_CAST_PLUS_WHITEBOARD", + static_cast(SubDeviceType::SUB_DEVICE_CAST_PLUS_WHITEBOARD)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportTriggerType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "UNSPEC_TAG", static_cast(TriggerType::UNSPEC_TAG)); + (void)SetNamedProperty(env, result, "PASSIVE_MATCH_TAG", static_cast(TriggerType::PASSIVE_MATCH_TAG)); + (void)SetNamedProperty(env, result, "ACTIVE_MATCH_TAG", static_cast(TriggerType::ACTIVE_MATCH_TAG)); + (void)SetNamedProperty(env, result, "PASSIVE_BIND_TAG", static_cast(TriggerType::PASSIVE_BIND_TAG)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportDeviceState(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "CONNECTING", static_cast(DeviceState::CONNECTING)); + (void)SetNamedProperty(env, result, "CONNECTED", static_cast(DeviceState::CONNECTED)); + (void)SetNamedProperty(env, result, "PAUSED", static_cast(DeviceState::PAUSED)); + (void)SetNamedProperty(env, result, "PLAYING", static_cast(DeviceState::PLAYING)); + (void)SetNamedProperty(env, result, "DISCONNECTING", static_cast(DeviceState::DISCONNECTING)); + (void)SetNamedProperty(env, result, "DISCONNECTED", static_cast(DeviceState::DISCONNECTED)); + (void)SetNamedProperty(env, result, "STREAM", static_cast(DeviceState::STREAM)); + (void)SetNamedProperty(env, result, "DEVICE_STATE_MAX", static_cast(DeviceState::DEVICE_STATE_MAX)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + + +static napi_value ExportServiceStatus(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "DISCONNECTED", static_cast(ServiceStatus::DISCONNECTED)); + (void)SetNamedProperty(env, result, "DISCONNECTING", static_cast(ServiceStatus::DISCONNECTING)); + (void)SetNamedProperty(env, result, "CONNECTING", static_cast(ServiceStatus::CONNECTING)); + (void)SetNamedProperty(env, result, "CONNECTED", static_cast(ServiceStatus::CONNECTED)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportDeviceStatusState(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "DEVICE_AVAILABLE", static_cast(DeviceStatusState::DEVICE_AVAILABLE)); + (void)SetNamedProperty(env, result, "DEVICE_CONNECTED", static_cast(DeviceStatusState::DEVICE_CONNECTED)); + (void)SetNamedProperty(env, result, "DEVICE_DISCONNECTED", + static_cast(DeviceStatusState::DEVICE_DISCONNECTED)); + (void)SetNamedProperty(env, result, "DEVICE_CONNECT_REQ", + static_cast(DeviceStatusState::DEVICE_CONNECT_REQ)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportPropertyType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "VIDEO_SIZE", static_cast(PropertyType::VIDEO_SIZE)); + (void)SetNamedProperty(env, result, "VIDEO_FPS", static_cast(PropertyType::VIDEO_FPS)); + (void)SetNamedProperty(env, result, "WINDOW_SIZE", static_cast(PropertyType::WINDOW_SIZE)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportChannelType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "SOFT_BUS", static_cast(ChannelType::SOFT_BUS)); + (void)SetNamedProperty(env, result, "LEGACY_CHANNEL", static_cast(ChannelType::LEGACY_CHANNEL)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportProtocolType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "CAST_PLUS_MIRROR", static_cast(ProtocolType::CAST_PLUS_MIRROR)); + (void)SetNamedProperty(env, result, "CAST_PLUS_STREAM", static_cast(ProtocolType::CAST_PLUS_STREAM)); + (void)SetNamedProperty(env, result, "MIRACAST", static_cast(ProtocolType::MIRACAST)); + (void)SetNamedProperty(env, result, "DLNA", static_cast(ProtocolType::DLNA)); + (void)SetNamedProperty(env, result, "COOPERATION", static_cast(ProtocolType::COOPERATION)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportEndType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "CAST_SINK", static_cast(EndType::CAST_SINK)); + (void)SetNamedProperty(env, result, "CAST_SOURCE", static_cast(EndType::CAST_SOURCE)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportEventId(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "EVENT_BEGIN", static_cast(EventId::EVENT_BEGIN)); + (void)SetNamedProperty(env, result, "EVENT_END", static_cast(EventId::EVENT_END)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportColorStandard(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "BT709", static_cast(ColorStandard::BT709)); + (void)SetNamedProperty(env, result, "BT601_PAL", static_cast(ColorStandard::BT601_PAL)); + (void)SetNamedProperty(env, result, "BT601_NTSC", static_cast(ColorStandard::BT601_NTSC)); + (void)SetNamedProperty(env, result, "BT2020", static_cast(ColorStandard::BT2020)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportVideoCodecType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "H264", static_cast(VideoCodecType::H264)); + (void)SetNamedProperty(env, result, "H265", static_cast(VideoCodecType::H265)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +static napi_value ExportCastModeType(napi_env env) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + + (void)SetNamedProperty(env, result, "MIRROR_CAST", static_cast(CastMode::MIRROR_CAST)); + (void)SetNamedProperty(env, result, "APP_CAST", static_cast(CastMode::APP_CAST)); + + NAPI_CALL(env, napi_object_freeze(env, result)); + return result; +} + +napi_status InitEnums(napi_env env, napi_value exports) +{ + const napi_property_descriptor properties[] = { + DECLARE_NAPI_PROPERTY("PlayerStates", ExportPlayerStates(env)), + DECLARE_NAPI_PROPERTY("PlaybackSpeed", ExportPlaybackSpeed(env)), + DECLARE_NAPI_PROPERTY("LoopMode", ExportLoopMode(env)), + DECLARE_NAPI_PROPERTY("DeviceType", ExportDeviceType(env)), + DECLARE_NAPI_PROPERTY("SubDeviceType", ExportSubDeviceType(env)), + DECLARE_NAPI_PROPERTY("TriggerType", ExportTriggerType(env)), + DECLARE_NAPI_PROPERTY("DeviceState", ExportDeviceState(env)), + DECLARE_NAPI_PROPERTY("ServiceStatus", ExportServiceStatus(env)), + DECLARE_NAPI_PROPERTY("DeviceStatusState", ExportDeviceStatusState(env)), + DECLARE_NAPI_PROPERTY("PropertyType", ExportPropertyType(env)), + DECLARE_NAPI_PROPERTY("ChannelType", ExportChannelType(env)), + DECLARE_NAPI_PROPERTY("ProtocolType", ExportProtocolType(env)), + DECLARE_NAPI_PROPERTY("EndType", ExportEndType(env)), + DECLARE_NAPI_PROPERTY("EventId", ExportEventId(env)), + DECLARE_NAPI_PROPERTY("ColorStandard", ExportColorStandard(env)), + DECLARE_NAPI_PROPERTY("VideoCodecType", ExportVideoCodecType(env)), + DECLARE_NAPI_PROPERTY("CastMode", ExportCastModeType(env)) + }; + + size_t count = sizeof(properties) / sizeof(napi_property_descriptor); + return napi_define_properties(env, exports, count, properties); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/interfaces/kits/js/src/napi_castengine_utils.cpp b/interfaces/kits/js/src/napi_castengine_utils.cpp new file mode 100644 index 0000000..6192377 --- /dev/null +++ b/interfaces/kits/js/src/napi_castengine_utils.cpp @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply untils realization for napi interface. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include +#include +#include "securec.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_cast_session.h" +#include "napi_castengine_utils.h" + +using namespace std; +using namespace OHOS::CastEngine; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-Utils"); + +napi_value GetUndefinedValue(napi_env env) +{ + napi_value result {}; + napi_get_undefined(env, &result); + return result; +} + +string ParseString(napi_env env, napi_value args) +{ + string result {}; + if (args == nullptr) { + CLOGE("args is nullptr"); + return result; + } + napi_valuetype valueType; + napi_status status = napi_typeof(env, args, &valueType); + CLOGD("param=%{public}d.", valueType); + if (status != napi_ok || valueType != napi_string) { + CLOGE("Wrong argument type. String expected."); + result = ""; + return result; + } + size_t size = 0; + size_t bufSize = 0; + + if (napi_get_value_string_utf8(env, args, nullptr, bufSize, &size) != napi_ok) { + CLOGE("can not get string size"); + result = ""; + return result; + } + result.reserve(size + 1); + result.resize(size); + if (napi_get_value_string_utf8(env, args, result.data(), (size + 1), &size) != napi_ok) { + CLOGE("can not get string value"); + result = ""; + return result; + } + return result; +} + +int32_t ParseInt32(napi_env env, napi_value args) +{ + int32_t param = 0; + if (args == nullptr) { + CLOGE("args is nullptr"); + return param; + } + napi_valuetype valueType; + napi_status status = napi_typeof(env, args, &valueType); + if (status != napi_ok) { + CLOGE("napi_typeof failed."); + return param; + } + CLOGD("param=%{public}d.", valueType); + if (valueType != napi_number) { + CLOGE("Wrong argument type. Int32 expected."); + return param; + } + status = napi_get_value_int32(env, args, ¶m); + if (status != napi_ok) { + CLOGE("napi_get_value_int32 failed."); + return param; + } + return param; +} + +bool ParseBool(napi_env env, napi_value args) +{ + bool param = false; + if (args == nullptr) { + CLOGE("args is nullptr"); + return param; + } + napi_valuetype valueType; + napi_status status = napi_typeof(env, args, &valueType); + if (status != napi_ok) { + CLOGE("napi_typeof failed."); + return param; + } + + CLOGD("param=%{public}d.", valueType); + if (valueType != napi_boolean) { + CLOGE("Wrong argument type. bool expected."); + return param; + } + status = napi_get_value_bool(env, args, ¶m); + if (status != napi_ok) { + CLOGE("napi_get_value_bool failed."); + return param; + } + return param; +} + +napi_value ConvertDeviceListToJS(napi_env env, const vector &devices) +{ + int count = 0; + napi_value devicesList = nullptr; + NAPI_CALL(env, napi_create_array(env, &devicesList)); + for (CastRemoteDevice vec : devices) { + napi_value deviceResult = ConvertCastRemoteDeviceToJS(env, vec); + NAPI_CALL(env, napi_set_element(env, devicesList, count, deviceResult)); + count++; + } + + if (devicesList == nullptr) { + CLOGE("devicesList is null"); + } + return devicesList; +} + +napi_value ConvertCastSessionToJS(napi_env env, const shared_ptr &castSession) +{ + napi_value napiCastSession; + NapiCastSession::CreateNapiCastSession(env, castSession, napiCastSession); + if (napiCastSession == nullptr) { + CLOGE("napiCastSession is null"); + } + return napiCastSession; +} + +napi_value ConvertDeviceStateInfoToJS(napi_env env, const DeviceStateInfo &stateEvent) +{ + napi_value stateEventCallback = nullptr; + napi_value deviceState = nullptr; + napi_value deviceId = nullptr; + + NAPI_CALL(env, napi_create_object(env, &stateEventCallback)); + NAPI_CALL(env, napi_create_string_utf8(env, stateEvent.deviceId.c_str(), NAPI_AUTO_LENGTH, &deviceId)); + NAPI_CALL(env, napi_create_int32(env, static_cast(stateEvent.deviceState), &deviceState)); + NAPI_CALL(env, napi_set_named_property(env, stateEventCallback, "deviceState", deviceState)); + NAPI_CALL(env, napi_set_named_property(env, stateEventCallback, "deviceId", deviceId)); + return stateEventCallback; +} + +CastRemoteDevice GetCastRemoteDeviceFromJS(napi_env env, napi_value &object) +{ + CastRemoteDevice castRemoteDevice = CastRemoteDevice(); + + castRemoteDevice.deviceId = JsObjectToString(env, object, "deviceId"); + castRemoteDevice.deviceName = JsObjectToString(env, object, "deviceName"); + int32_t deviceTypeCallback = JsObjectToInt32(env, object, "deviceType"); + DeviceType deviceType = static_cast(deviceTypeCallback); + int32_t subDeviceTypeCallback = JsObjectToInt32(env, object, "subDeviceType"); + SubDeviceType subDeviceType = static_cast(subDeviceTypeCallback); + castRemoteDevice.ipAddress = JsObjectToString(env, object, "ipAddress"); + int32_t channelTypeInt = JsObjectToInt32(env, object, "channelType"); + ChannelType channelType = static_cast(channelTypeInt); + + castRemoteDevice.deviceType = deviceType; + castRemoteDevice.subDeviceType = subDeviceType; + castRemoteDevice.channelType = channelType; + return castRemoteDevice; +} + +WindowProperty GetWindowPropertyFromJS(napi_env env, napi_value &object) +{ + WindowProperty windowProperty = WindowProperty(); + + napi_value windowPropertyCallback = nullptr; + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, "windowProperty", &hasProperty); + if (status == napi_ok && hasProperty) { + status = napi_get_named_property(env, object, "windowProperty", &windowPropertyCallback); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return windowProperty; + } + uint32_t width = JsObjectToUint32(env, windowPropertyCallback, "width"); + uint32_t height = JsObjectToUint32(env, windowPropertyCallback, "height"); + uint32_t startX = JsObjectToUint32(env, windowPropertyCallback, "startX"); + uint32_t startY = JsObjectToUint32(env, windowPropertyCallback, "startY"); + + windowProperty.startX = startX; + windowProperty.startY = startY; + windowProperty.width = width; + windowProperty.height = height; + } + return windowProperty; +} + +bool GetProtocolTypesFromJS(napi_env env, napi_value &object, int &protocolTypes) +{ + bool isArray = false; + NAPI_CALL_BASE(env, napi_is_array(env, object, &isArray), false); + if (!isArray) { + CLOGE("protocolType is not array."); + return false; + } + uint32_t arrLen = 0; + NAPI_CALL_BASE(env, napi_get_array_length(env, object, &arrLen), false); + if (arrLen == 0) { + CLOGE("mediaInfoList len is invalid"); + return false; + } + uint32_t ret = 0; + for (uint32_t i = 0; i < arrLen; i++) { + napi_value item = nullptr; + NAPI_CALL_BASE(env, napi_get_element(env, object, i, &item), false); + ret = ret | static_cast(ParseInt32(env, item)); + } + protocolTypes = static_cast(ret); + CLOGI("GetProtocolTypesFromJS finished, protocolTypes: %{public}d", protocolTypes); + return true; +} + +bool GetMediaInfoHolderFromJS(napi_env env, napi_value &object, MediaInfoHolder &mediaInfoHolder) +{ + napi_value mediaInfoList = nullptr; + bool hasProperty = false; + + mediaInfoHolder.currentIndex = JsObjectToUint32(env, object, "currentIndex"); + mediaInfoHolder.progressRefreshInterval = JsObjectToUint32(env, object, "progressRefreshInterval"); + NAPI_CALL_BASE(env, napi_has_named_property(env, object, "mediaInfoList", &hasProperty), false); + if (!hasProperty) { + CLOGE("mediaInfoList is not exit"); + return false; + } + NAPI_CALL_BASE(env, napi_get_named_property(env, object, "mediaInfoList", &mediaInfoList), false); + bool isArray = false; + NAPI_CALL_BASE(env, napi_is_array(env, mediaInfoList, &isArray), false); + if (!isArray) { + CLOGE("mediaInfoList is not array."); + return false; + } + uint32_t arrLen = 0; + NAPI_CALL_BASE(env, napi_get_array_length(env, mediaInfoList, &arrLen), false); + if (arrLen == 0) { + CLOGE("mediaInfoList len is invalid"); + return false; + } + for (uint32_t i = 0; i < arrLen; i++) { + napi_value item = nullptr; + NAPI_CALL_BASE(env, napi_get_element(env, mediaInfoList, i, &item), false); + MediaInfo mediaInfo = MediaInfo{}; + GetMediaInfoFromJS(env, item, mediaInfo); + mediaInfoHolder.mediaInfoList.push_back(mediaInfo); + } + return true; +} + +bool GetMediaInfoFromJS(napi_env env, napi_value &object, MediaInfo &mediaInfo) +{ + mediaInfo.mediaId = JsObjectToString(env, object, "mediaId"); + mediaInfo.mediaName = JsObjectToString(env, object, "mediaName"); + mediaInfo.mediaUrl = JsObjectToString(env, object, "mediaUrl"); + mediaInfo.mediaType = JsObjectToString(env, object, "mediaType"); + mediaInfo.albumCoverUrl = JsObjectToString(env, object, "albumCoverUrl"); + mediaInfo.albumTitle = JsObjectToString(env, object, "albumTitle"); + mediaInfo.mediaArtist = JsObjectToString(env, object, "mediaArtist"); + mediaInfo.lrcUrl = JsObjectToString(env, object, "lrcUrl"); + mediaInfo.lrcContent = JsObjectToString(env, object, "lrcContent"); + mediaInfo.appIconUrl = JsObjectToString(env, object, "appIconUrl"); + mediaInfo.appName = JsObjectToString(env, object, "appName"); + mediaInfo.mediaSize = JsObjectToUint32(env, object, "mediaSize"); + mediaInfo.startPosition = JsObjectToUint32(env, object, "startPosition"); + mediaInfo.duration = JsObjectToUint32(env, object, "duration"); + mediaInfo.closingCreditsPosition = JsObjectToUint32(env, object, "closingCreditsPosition"); + return true; +} + +CastSessionProperty GetCastSessionPropertyFromJS(napi_env env, napi_value &object) +{ + CastSessionProperty castSessionProperty = CastSessionProperty(); + + int32_t protocolTypeInt = JsObjectToInt32(env, object, "protocolType"); + ProtocolType protocolType = static_cast(protocolTypeInt); + int32_t endTypeInt = JsObjectToInt32(env, object, "endType"); + EndType endType = static_cast(endTypeInt); + napi_value audioPropertyCallback = nullptr; + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, "audioProperty", &hasProperty); + if (status == napi_ok && hasProperty) { + status = napi_get_named_property(env, object, "audioProperty", &audioPropertyCallback); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return castSessionProperty; + } + AudioProperty audioProperty = GetAudioPropertyFromJS(env, audioPropertyCallback); + castSessionProperty.audioProperty = audioProperty; + } + + napi_value videoPropertyCallback = nullptr; + hasProperty = false; + status = napi_has_named_property(env, object, "videoProperty", &hasProperty); + if (status == napi_ok && hasProperty) { + status = napi_get_named_property(env, object, "videoProperty", &videoPropertyCallback); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return castSessionProperty; + } + VideoProperty videoProperty = GetVideoPropertyFromJS(env, videoPropertyCallback); + castSessionProperty.videoProperty = videoProperty; + } + WindowProperty windowProperty = GetWindowPropertyFromJS(env, object); + + castSessionProperty.protocolType = protocolType; + castSessionProperty.endType = endType; + castSessionProperty.windowProperty = windowProperty; + return castSessionProperty; +} + +AudioProperty GetAudioPropertyFromJS(napi_env env, napi_value &object) +{ + AudioProperty audioProperty = AudioProperty(); + + uint32_t sampleRate = JsObjectToUint32(env, object, "sampleRate"); + uint32_t channelConfig = JsObjectToUint32(env, object, "channelConfig"); + uint32_t bitrate = JsObjectToUint32(env, object, "bitrate"); + uint32_t codec = JsObjectToUint32(env, object, "codec"); + + audioProperty.sampleRate = sampleRate; + audioProperty.channelConfig = channelConfig; + audioProperty.bitrate = bitrate; + audioProperty.codec = codec; + return audioProperty; +} + +VideoProperty GetVideoPropertyFromJS(napi_env env, napi_value &object) +{ + VideoProperty videoProperty = VideoProperty(); + uint32_t videoWidth = JsObjectToUint32(env, object, "videoWidth"); + uint32_t videoHeight = JsObjectToUint32(env, object, "videoHeight"); + uint32_t fps = JsObjectToUint32(env, object, "fps"); + int32_t codecTypeInt = JsObjectToInt32(env, object, "codecType"); + VideoCodecType codecType = static_cast(codecTypeInt); + uint32_t gop = JsObjectToUint32(env, object, "gop"); + uint32_t bitrate = JsObjectToUint32(env, object, "bitrate"); + uint32_t minBitrate = JsObjectToUint32(env, object, "minBitrate"); + uint32_t maxBitrate = JsObjectToUint32(env, object, "maxBitrate"); + uint32_t dpi = JsObjectToUint32(env, object, "dpi"); + int32_t colorStandardInt = JsObjectToInt32(env, object, "colorStandard"); + ColorStandard colorStandard = static_cast(colorStandardInt); + uint32_t screenWidth = JsObjectToUint32(env, object, "screenWidth"); + uint32_t screenHeight = JsObjectToUint32(env, object, "screenHeight"); + uint32_t profile = JsObjectToUint32(env, object, "profile"); + uint32_t level = JsObjectToUint32(env, object, "level"); + + videoProperty.videoWidth = videoWidth; + videoProperty.videoHeight = videoHeight; + videoProperty.fps = fps; + videoProperty.codecType = codecType; + videoProperty.gop = gop; + videoProperty.bitrate = bitrate; + videoProperty.minBitrate = minBitrate; + videoProperty.maxBitrate = maxBitrate; + videoProperty.dpi = dpi; + videoProperty.colorStandard = colorStandard; + videoProperty.screenWidth = screenWidth; + videoProperty.screenHeight = screenHeight; + videoProperty.profile = profile; + videoProperty.level = level; + return videoProperty; +} + +bool Equals(napi_env env, napi_value value, napi_ref copy) +{ + if (copy == nullptr) { + return (value == nullptr); + } + + napi_value copyValue = nullptr; + if (napi_get_reference_value(env, copy, ©Value) != napi_ok) { + CLOGE("get ref value failed"); + return false; + } + bool isEquals = false; + if (napi_strict_equals(env, value, copyValue, &isEquals) != napi_ok) { + CLOGE("get equals result failed"); + return false; + } + return isEquals; +} + +napi_status GetRefByCallback(napi_env env, std::list callbackList, napi_value callback, napi_ref &callbackRef) +{ + for (auto ref = callbackList.begin(); ref != callbackList.end(); ++ref) { + if (Equals(env, callback, *ref)) { + CLOGD("Callback has been matched"); + callbackRef = *ref; + break; + } + } + return napi_ok; +} + +napi_value ConvertCastRemoteDeviceToJS(napi_env env, const CastRemoteDevice &castRemoteDevice) +{ + napi_value result = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + napi_value deviceId = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, castRemoteDevice.deviceId.c_str(), NAPI_AUTO_LENGTH, &deviceId)); + NAPI_CALL(env, napi_set_named_property(env, result, "deviceId", deviceId)); + napi_value deviceName = nullptr; + CLOGD("ConvertCastRemoteDeviceToJS deviceName %{public}s", castRemoteDevice.deviceName.c_str()); + NAPI_CALL(env, napi_create_string_utf8(env, castRemoteDevice.deviceName.c_str(), NAPI_AUTO_LENGTH, &deviceName)); + NAPI_CALL(env, napi_set_named_property(env, result, "deviceName", deviceName)); + napi_value deviceType = nullptr; + NAPI_CALL(env, napi_create_int32(env, static_cast(castRemoteDevice.deviceType), &deviceType)); + NAPI_CALL(env, napi_set_named_property(env, result, "deviceType", deviceType)); + napi_value subDeviceType = nullptr; + NAPI_CALL(env, napi_create_int32(env, static_cast(castRemoteDevice.subDeviceType), &subDeviceType)); + NAPI_CALL(env, napi_set_named_property(env, result, "subDeviceType", subDeviceType)); + napi_value ipAddress = nullptr; + NAPI_CALL(env, napi_create_string_utf8(env, castRemoteDevice.ipAddress.c_str(), NAPI_AUTO_LENGTH, &ipAddress)); + NAPI_CALL(env, napi_set_named_property(env, result, "ipAddress", ipAddress)); + napi_value channelType = nullptr; + NAPI_CALL(env, napi_create_int32(env, static_cast(castRemoteDevice.channelType), &channelType)); + NAPI_CALL(env, napi_set_named_property(env, result, "channelType", channelType)); + return result; +} + +string JsObjectToString(napi_env env, napi_value &object, const char *fieldStr) +{ + string fieldRef {}; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + napi_value field = nullptr; + bool hasProperty = false; + + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return fieldRef; + } + fieldRef = ParseString(env, field); + return fieldRef; + } else { + CLOGE("Js obj to str no property: %{public}s", fieldStr); + } + return fieldRef; +} + +int32_t JsObjectToInt32(napi_env env, napi_value &object, const char *fieldStr) +{ + int32_t fieldRef = 0; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value field; + napi_valuetype valueType; + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return fieldRef; + } + status = napi_typeof(env, field, &valueType); + if (status != napi_ok || valueType != napi_number) { + CLOGE("Wrong argument type. Number expected."); + return fieldRef; + } + status = napi_get_value_int32(env, field, &fieldRef); + if (status != napi_ok) { + CLOGE("napi_get_value_int32 failed"); + return fieldRef; + } + return fieldRef; + } else { + CLOGE("Js to int32_t no property: %{public}s", fieldStr); + } + return fieldRef; +} + +bool JsObjectToBool(napi_env env, napi_value &object, const char *fieldStr) +{ + bool fieldRef = false; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value field; + napi_valuetype valueType; + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return fieldRef; + } + status = napi_typeof(env, field, &valueType); + if (status != napi_ok || valueType != napi_boolean) { + CLOGE("Wrong argument type. Bool expected."); + return fieldRef; + } + status = napi_get_value_bool(env, field, &fieldRef); + if (status != napi_ok) { + CLOGE("napi_get_value_bool failed"); + return fieldRef; + } + return fieldRef; + } else { + CLOGE("Js to bool no property: %{public}s", fieldStr); + } + return fieldRef; +} + +uint32_t JsObjectToUint32(napi_env env, napi_value &object, const char *fieldStr) +{ + uint32_t fieldRef = 0; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value field; + napi_valuetype valueType; + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return fieldRef; + } + status = napi_typeof(env, field, &valueType); + if (status != napi_ok || valueType != napi_number) { + CLOGE("Wrong argument type. Number expected."); + return fieldRef; + } + status = napi_get_value_uint32(env, field, &fieldRef); + if (status != napi_ok) { + CLOGE("napi_get_value_uint32 failed"); + return fieldRef; + } + return fieldRef; + } else { + CLOGE("Js to uint32_t no property: %{public}s", fieldStr); + } + return fieldRef; +} + +double JsObjectToDouble(napi_env env, napi_value &object, const char *fieldStr) +{ + double fieldRef = 0; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value field; + napi_valuetype valueType; + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed."); + return fieldRef; + } + status = napi_typeof(env, field, &valueType); + if (status != napi_ok || valueType != napi_number) { + CLOGE("Wrong argument type. Number expected."); + return fieldRef; + } + status = napi_get_value_double(env, field, &fieldRef); + if (status != napi_ok) { + CLOGE("napi_get_value_double failed"); + return fieldRef; + } + return fieldRef; + } else { + CLOGE("Js to double no property: %{public}s", fieldStr); + } + return fieldRef; +} + +int64_t JsObjectToInt64(napi_env env, napi_value &object, const char *fieldStr) +{ + int64_t fieldRef = 0; + if (object == nullptr) { + CLOGE("args is nullptr"); + return fieldRef; + } + bool hasProperty = false; + napi_status status = napi_has_named_property(env, object, fieldStr, &hasProperty); + if (status == napi_ok && hasProperty) { + napi_value field; + napi_valuetype valueType; + status = napi_get_named_property(env, object, fieldStr, &field); + if (status != napi_ok) { + CLOGE("napi_get_named_property failed"); + return fieldRef; + } + status = napi_typeof(env, field, &valueType); + if (status != napi_ok || valueType != napi_number) { + CLOGE("Wrong argument type. Number expected."); + return fieldRef; + } + status = napi_get_value_int64(env, field, &fieldRef); + if (status != napi_ok) { + CLOGE("napi_get_value_int64 failed"); + return fieldRef; + } + return fieldRef; + } else { + CLOGE("Js to int64_t no property: %{public}s", fieldStr); + } + return fieldRef; +} + +napi_value ConvertMediaInfoToJS(napi_env env, const MediaInfo &mediaInfo) +{ + CLOGD("ConvertMediaInfoToJS start"); + napi_value result = nullptr; + napi_value value = nullptr; + NAPI_CALL(env, napi_create_object(env, &result)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.mediaId.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaId", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.mediaName.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaName", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.mediaUrl.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaUrl", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.mediaType.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaType", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.albumCoverUrl.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "albumCoverUrl", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.albumTitle.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "albumTitle", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.mediaArtist.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaArtist", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.lrcUrl.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "lrcUrl", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.lrcContent.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "lrcContent", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.appIconUrl.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "appIconUrl", value)); + NAPI_CALL(env, napi_create_string_utf8(env, mediaInfo.appName.c_str(), NAPI_AUTO_LENGTH, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "appName", value)); + + NAPI_CALL(env, napi_create_uint32(env, mediaInfo.mediaSize, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "mediaSize", value)); + NAPI_CALL(env, napi_create_uint32(env, mediaInfo.startPosition, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "startPosition", value)); + NAPI_CALL(env, napi_create_uint32(env, mediaInfo.duration, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "duration", value)); + NAPI_CALL(env, napi_create_uint32(env, mediaInfo.closingCreditsPosition, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "closingCreditsPosition", value)); + CLOGD("ConvertMediaInfoToJS end"); + + return result; +} + +napi_value ConvertMediaInfoHolderToJS(napi_env env, const MediaInfoHolder &mediaInfoHolder) +{ + CLOGD("ConvertMediaInfoHolderToJS start"); + napi_value result = nullptr; + napi_value value = nullptr; + size_t len = mediaInfoHolder.mediaInfoList.size(); + if (len == 0) { + CLOGE("mediaInfoList len is invalid"); + return result; + } + NAPI_CALL(env, napi_create_object(env, &result)); + NAPI_CALL(env, napi_create_uint32(env, mediaInfoHolder.currentIndex, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "currentIndex", value)); + NAPI_CALL(env, napi_create_uint32(env, mediaInfoHolder.progressRefreshInterval, &value)); + NAPI_CALL(env, napi_set_named_property(env, result, "progressRefreshInterval", value)); + NAPI_CALL(env, napi_create_array_with_length(env, len, &value)); + for (size_t i = 0; i < len; i++) { + napi_value mediaInfo = ConvertMediaInfoToJS(env, mediaInfoHolder.mediaInfoList[i]); + NAPI_CALL(env, napi_set_element(env, value, i, mediaInfo)); + } + NAPI_CALL(env, napi_set_named_property(env, result, "mediaInfoList", value)); + CLOGD("ConvertMediaInfoHolderToJS end"); + return result; +} + +void CallJSFunc(napi_env env, napi_ref func, size_t argc, napi_value argv[]) +{ + napi_value callback = nullptr; + napi_value undefined = nullptr; + napi_value callResult = nullptr; + if (napi_get_undefined(env, &undefined) != napi_ok) { + CLOGE("napi_get_undefined failed"); + return; + } + if (napi_get_reference_value(env, func, &callback) != napi_ok) { + CLOGE("napi_get_reference_value failed"); + return; + } + if (napi_call_function(env, undefined, callback, argc, argv, &callResult) != napi_ok) { + CLOGE("napi_call_function failed"); + } +} + +bool GetJSFuncParams(napi_env env, napi_callback_info info, napi_value argv[], size_t expectedArgc, + napi_valuetype expectedTypes[]) +{ + napi_value thisVar = nullptr; + size_t argc = expectedArgc; + napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); + if (status != napi_ok || argc != expectedArgc) { + CLOGE("napi_get_cb_info failed"); + return false; + } + + for (size_t i = 0; i < expectedArgc; i++) { + napi_valuetype valueType = napi_undefined; + if (napi_typeof(env, argv[i], &valueType) != napi_ok) { + CLOGE("napi_typeof failed"); + return false; + } + if (valueType != expectedTypes[i]) { + CLOGE("Wrong argument type. type:%d expected", expectedTypes[i]); + return false; + } + } + + return true; +} + +bool CheckJSParamsType(napi_env env, napi_value argv[], size_t expectedArgc, napi_valuetype expectedTypes[]) +{ + for (size_t i = 0; i < expectedArgc; i++) { + napi_valuetype valueType = napi_undefined; + if (napi_typeof(env, argv[i], &valueType) != napi_ok) { + CLOGE("napi_typeof failed"); + return false; + } + if (valueType != expectedTypes[i]) { + CLOGE("Wrong argument type. type:%d expected", expectedTypes[i]); + return false; + } + } + + return true; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/interfaces/kits/js/src/napi_mirror_player.cpp b/interfaces/kits/js/src/napi_mirror_player.cpp new file mode 100644 index 0000000..06f65ee --- /dev/null +++ b/interfaces/kits/js/src/napi_mirror_player.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface realization for cast mirror player. + * Author: zhangjingnan + * Create: 2023-5-27 + */ + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "oh_remote_control_event.h" +#include "i_mirror_player.h" +#include "napi_castengine_utils.h" +#include "napi_mirror_player.h" +#include "napi_async_work.h" + +using namespace OHOS::CastEngine::CastEngineClient; +using namespace std; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-MirrorPlayer"); + +thread_local napi_ref NapiMirrorPlayer::consRef_ = nullptr; + +void NapiMirrorPlayer::DefineMirrorPlayerJSClass(napi_env env) +{ + napi_property_descriptor NapiMirrorPlayerDesc[] = { + DECLARE_NAPI_FUNCTION("play", Play), + DECLARE_NAPI_FUNCTION("pause", Pause), + DECLARE_NAPI_FUNCTION("setSurface", SetSurface), + DECLARE_NAPI_FUNCTION("release", Release) + }; + + napi_value mirrorPlayer = nullptr; + constexpr int initialRefCount = 1; + napi_status status = napi_define_class(env, "mirrorPlayer", NAPI_AUTO_LENGTH, NapiMirrorPlayerConstructor, nullptr, + sizeof(NapiMirrorPlayerDesc) / sizeof(NapiMirrorPlayerDesc[0]), NapiMirrorPlayerDesc, &mirrorPlayer); + if (status != napi_ok) { + CLOGE("napi_define_class failed"); + return; + } + status = napi_create_reference(env, mirrorPlayer, initialRefCount, &consRef_); + if (status != napi_ok) { + CLOGE("DefineMirrorPlayerJSClass napi_create_reference failed"); + } +} + +napi_value NapiMirrorPlayer::NapiMirrorPlayerConstructor(napi_env env, napi_callback_info info) +{ + CLOGD("NapiMirrorPlayer start to construct in"); + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); + CLOGD("NapiMirrorPlayer construct successfully"); + return thisVar; +} + +napi_status NapiMirrorPlayer::CreateNapiMirrorPlayer(napi_env env, shared_ptr player, napi_value &out) +{ + CLOGD("Start to create napiMirrorPlayer in"); + napi_value result = nullptr; + napi_value constructor = nullptr; + if (consRef_ == nullptr || player == nullptr) { + CLOGE("CreateNapiMirrorPlayer input is null"); + return napi_generic_failure; + } + napi_status status = napi_get_reference_value(env, consRef_, &constructor); + if (status != napi_ok || constructor == nullptr) { + CLOGE("CreateNapiMirrorPlayer napi_get_reference_value failed"); + return napi_generic_failure; + } + + constexpr size_t argc = 0; + status = napi_new_instance(env, constructor, argc, nullptr, &result); + if (status != napi_ok) { + CLOGE("CreateNapiMirrorPlayer napi_new_instance failed"); + return napi_generic_failure; + } + + NapiMirrorPlayer *napiMirrorPlayer = new NapiMirrorPlayer(player); + if (napiMirrorPlayer == nullptr) { + CLOGE("NapiMirrorPlayer is nullptr"); + return napi_generic_failure; + } + auto finalize = [](napi_env env, void *data, void *hint) { + NapiMirrorPlayer *player = reinterpret_cast(data); + if (player != nullptr) { + CLOGI("Session deconstructed"); + delete player; + player = nullptr; + } + }; + if (napi_wrap(env, result, napiMirrorPlayer, finalize, nullptr, nullptr) != napi_ok) { + CLOGE("CreateNapiMirrorPlayer napi_wrap failed"); + delete napiMirrorPlayer; + napiMirrorPlayer = nullptr; + return napi_generic_failure; + } + out = result; + CLOGD("Create napiMirrorPlayer successfully"); + return napi_ok; +} + +napi_value NapiMirrorPlayer::Play(napi_env env, napi_callback_info info) +{ + CLOGD("Start to play in"); + struct ConcreteTask : public NapiAsyncTask { + string deviceId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->deviceId_ = ParseString(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr mirrorPlayer = napiPlayer->GetMirrorPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = mirrorPlayer->Play(napiAsyntask->deviceId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Play failed : no permission"; + } else { + napiAsyntask->errMessage = "Play failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Play", executor, complete); +} + +napi_value NapiMirrorPlayer::Pause(napi_env env, napi_callback_info info) +{ + CLOGD("Start to pause in"); + struct ConcreteTask : public NapiAsyncTask { + string deviceId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->deviceId_ = ParseString(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr mirrorPlayer = napiPlayer->GetMirrorPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = mirrorPlayer->Pause(napiAsyntask->deviceId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Pause failed : no permission"; + } else { + napiAsyntask->errMessage = "Pause failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Pause", executor, complete); +} + +napi_value NapiMirrorPlayer::SetSurface(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set surface in"); + struct ConcreteTask : public NapiAsyncTask { + string surfaceId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->surfaceId_ = ParseString(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr mirrorPlayer = napiPlayer->GetMirrorPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = mirrorPlayer->SetSurface(napiAsyntask->surfaceId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetSurface failed : no permission"; + } else { + napiAsyntask->errMessage = "SetSurface failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetSurface", executor, complete); +} + +napi_value NapiMirrorPlayer::Release(napi_env env, napi_callback_info info) +{ + CLOGD("Start to release in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + napiAsyntask->GetJSInfo(env, info); + + auto executor = [napiAsyntask]() { + auto *napiPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiPlayer != nullptr, "napiPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + shared_ptr mirrorPlayer = napiPlayer->GetMirrorPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, mirrorPlayer, "IMirrorPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = mirrorPlayer->Release(); + if (ret == CAST_ENGINE_SUCCESS) { + napiPlayer->Reset(); + } else if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Release failed : no permission"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } else { + napiAsyntask->errMessage = "Release failed : native server exception"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_stream_player.cpp b/interfaces/kits/js/src/napi_stream_player.cpp new file mode 100644 index 0000000..13728b9 --- /dev/null +++ b/interfaces/kits/js/src/napi_stream_player.cpp @@ -0,0 +1,1552 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply napi interface realization for stream player. + * Author: huangchanggui + * Create: 2023-1-11 + */ + +#include "napi_stream_player.h" +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_castengine_utils.h" +#include "napi_async_work.h" +#include "napi_errors.h" +#include "cast_engine_errors.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-StreamPlayer"); + +thread_local napi_ref NapiStreamPlayer::consRef_ = nullptr; + +std::map> + NapiStreamPlayer::eventHandlers_ = { + { "stateChanged", { OnStateChanged, OffStateChanged } }, + { "positionChanged", { OnPositionChanged, OffPositionChanged } }, + { "mediaItemChanged", { OnMediaItemChanged, OffMediaItemChanged } }, + { "volumeChanged", { OnVolumeChanged, OffVolumeChanged } }, + { "videoSizeChanged", { OnVideoSizeChanged, OffVideoSizeChanged } }, + { "loopModeChanged", { OnLoopModeChanged, OffLoopModeChanged } }, + { "playSpeedChanged", { OnPlaySpeedChanged, OffPlaySpeedChanged } }, + { "playerError", { OnPlayerError, OffPlayerError } }, + { "nextRequest", { OnNextRequest, OffNextRequest } }, + { "previousRequest", { OnPreviousRequest, OffPreviousRequest } }, + { "seekDone", { OnSeekDone, OffSeekDone } }, + { "endOfStream", { OnEndOfStream, OffEndOfStream } } +}; + +void NapiStreamPlayer::DefineStreamPlayerJSClass(napi_env env) +{ + napi_property_descriptor playerDesc[] = { + DECLARE_NAPI_FUNCTION("on", OnEvent), + DECLARE_NAPI_FUNCTION("off", OffEvent), + DECLARE_NAPI_FUNCTION("setSurface", SetSurface), + DECLARE_NAPI_FUNCTION("load", Load), + DECLARE_NAPI_FUNCTION("start", Start), + DECLARE_NAPI_FUNCTION("play", Play), + DECLARE_NAPI_FUNCTION("pause", Pause), + DECLARE_NAPI_FUNCTION("stop", Stop), + DECLARE_NAPI_FUNCTION("next", Next), + DECLARE_NAPI_FUNCTION("previous", Previous), + DECLARE_NAPI_FUNCTION("seek", Seek), + DECLARE_NAPI_FUNCTION("fastForward", FastForward), + DECLARE_NAPI_FUNCTION("fastRewind", FastRewind), + DECLARE_NAPI_FUNCTION("setVolume", SetVolume), + DECLARE_NAPI_FUNCTION("setLoopMode", SetLoopMode), + DECLARE_NAPI_FUNCTION("setSpeed", SetSpeed), + DECLARE_NAPI_FUNCTION("getPlayerStatus", GetPlayerStatus), + DECLARE_NAPI_FUNCTION("getPosition", GetPosition), + DECLARE_NAPI_FUNCTION("getVolume", GetVolume), + DECLARE_NAPI_FUNCTION("getLoopMode", GetLoopMode), + DECLARE_NAPI_FUNCTION("getPlaySpeed", GetPlaySpeed), + DECLARE_NAPI_FUNCTION("getMediaInfoHolder", GetMediaInfoHolder), + DECLARE_NAPI_FUNCTION("release", Release) + }; + + napi_value constructor = nullptr; + constexpr int initialRefCount = 1; + napi_status status = napi_define_class(env, "streamPlayer", NAPI_AUTO_LENGTH, NapiStreamPlayerConstructor, nullptr, + sizeof(playerDesc) / sizeof(playerDesc[0]), playerDesc, &constructor); + if (status != napi_ok) { + CLOGE("napi_define_class failed"); + return; + } + status = napi_create_reference(env, constructor, initialRefCount, &consRef_); + if (status != napi_ok) { + CLOGE("DefineStreamPlayerJSClass napi_create_reference failed"); + } +} + +napi_value NapiStreamPlayer::NapiStreamPlayerConstructor(napi_env env, napi_callback_info info) +{ + CLOGD("NapiStreamPlayer construct in"); + napi_value thisVar = nullptr; + NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); + CLOGD("NapiStreamPlayer construct successfully"); + return thisVar; +} + +napi_status NapiStreamPlayer::CreateNapiStreamPlayer(napi_env env, std::shared_ptr player, + napi_value &out) +{ + CLOGD("create napiStreamPlayer in"); + napi_value result = nullptr; + napi_value constructor = nullptr; + if (consRef_ == nullptr || player == nullptr) { + CLOGE("napiStreamPlayer input is null"); + return napi_generic_failure; + } + napi_status status = napi_get_reference_value(env, consRef_, &constructor); + if (status != napi_ok || constructor == nullptr) { + CLOGE("CreateNapiStreamPlayer napi_get_reference_value failed"); + return napi_generic_failure; + } + + constexpr size_t argc = 0; + status = napi_new_instance(env, constructor, argc, nullptr, &result); + if (status != napi_ok) { + CLOGE("CreateNapiStreamPlayer napi_new_instance failed"); + return napi_generic_failure; + } + + NapiStreamPlayer *napiStreamPlayer = new NapiStreamPlayer(player); + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is nullptr"); + return napi_generic_failure; + } + auto finalize = [](napi_env env, void *data, void *hint) { + NapiStreamPlayer *napiStreamPlayer = reinterpret_cast(data); + if (napiStreamPlayer != nullptr) { + CLOGI("napiStreamPlayer deconstructed"); + delete napiStreamPlayer; + napiStreamPlayer = nullptr; + } + }; + if (napi_wrap(env, result, napiStreamPlayer, finalize, nullptr, nullptr) != napi_ok) { + CLOGE("CreateNapiStreamPlayer napi_wrap failed"); + delete napiStreamPlayer; + napiStreamPlayer = nullptr; + return napi_generic_failure; + } + out = result; + CLOGD("Create napiStreamPlayer successfully"); + return napi_ok; +} + +NapiStreamPlayer *NapiStreamPlayer::GetNapiStreamPlayer(napi_env env, napi_callback_info info) +{ + napi_value thisVar = nullptr; + NAPI_CALL_BASE(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), nullptr); + + NapiStreamPlayer *napiStreamPlayer = nullptr; + NAPI_CALL_BASE(env, napi_unwrap(env, thisVar, reinterpret_cast(&napiStreamPlayer)), nullptr); + if (napiStreamPlayer == nullptr) { + CLOGE("napi_unwrap napiStreamPlayer is null"); + return nullptr; + } + + return napiStreamPlayer; +} + +napi_value NapiStreamPlayer::OnEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function }; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + + std::string eventName = ParseString(env, argv[0]); + NapiStreamPlayer *napiStreamPlayer = GetNapiStreamPlayer(env, info); + if (napiStreamPlayer == nullptr) { + CLOGE("IStreamPlayer is null"); + return GetUndefinedValue(env); + } + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + + if (RegisterNativeStreamPlayerListener(napiStreamPlayer) == napi_generic_failure) { + return GetUndefinedValue(env); + } + if (it->second.first(env, argv[1], napiStreamPlayer) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_value NapiStreamPlayer::OffEvent(napi_env env, napi_callback_info info) +{ + constexpr size_t expectedArgc = 2; + napi_value argv[expectedArgc] = { 0 }; + napi_valuetype expectedTypes[expectedArgc] = { napi_string, napi_function}; + if (!GetJSFuncParams(env, info, argv, expectedArgc, expectedTypes)) { + return GetUndefinedValue(env); + } + + std::string eventName = ParseString(env, argv[0]); + auto it = eventHandlers_.find(eventName); + if (it == eventHandlers_.end()) { + CLOGE("event name invalid"); + return GetUndefinedValue(env); + } + NapiStreamPlayer *napiStreamPlayer = GetNapiStreamPlayer(env, info); + if (napiStreamPlayer == nullptr) { + CLOGE("IStreamPlayer is null"); + return GetUndefinedValue(env); + } + if (it->second.second(env, argv[1], napiStreamPlayer) != napi_ok) { + CLOGE("event name invalid"); + } + + return GetUndefinedValue(env); +} + +napi_status NapiStreamPlayer::OnStateChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_PLAYER_STATUS_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnPositionChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_POSITION_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnMediaItemChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_MEDIA_ITEM_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnVolumeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_VOLUME_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnVideoSizeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_VIDEO_SIZE_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnLoopModeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_LOOP_MODE_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnPlaySpeedChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_PLAY_SPEED_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnPlayerError(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_PLAYER_ERROR, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnNextRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_NEXT_REQUEST, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnPreviousRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_PREVIOUS_REQUEST, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnSeekDone(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_SEEK_DONE, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OnEndOfStream(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->AddCallback(env, NapiStreamPlayerListener::EVENT_END_OF_STREAM, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffStateChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, + NapiStreamPlayerListener::EVENT_PLAYER_STATUS_CHANGED, callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffPositionChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_POSITION_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffMediaItemChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_MEDIA_ITEM_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffVolumeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_VOLUME_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffVideoSizeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_VIDEO_SIZE_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffLoopModeChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_LOOP_MODE_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffPlaySpeedChanged(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_PLAY_SPEED_CHANGED, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffPlayerError(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_PLAYER_ERROR, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffNextRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_NEXT_REQUEST, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffPreviousRequest(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_PREVIOUS_REQUEST, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffSeekDone(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_SEEK_DONE, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::OffEndOfStream(napi_env env, napi_value callback, NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (!napiStreamPlayer->NapiListenerGetter()) { + CLOGE("napi stream player callback is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()->RemoveCallback(env, NapiStreamPlayerListener::EVENT_END_OF_STREAM, + callback) != napi_ok) { + return napi_generic_failure; + } + return napi_ok; +} + +napi_status NapiStreamPlayer::RegisterNativeStreamPlayerListener(NapiStreamPlayer *napiStreamPlayer) +{ + if (napiStreamPlayer == nullptr) { + CLOGE("napiStreamPlayer is null"); + return napi_generic_failure; + } + if (napiStreamPlayer->NapiListenerGetter()) { + return napi_ok; + } + auto streamPlayer = napiStreamPlayer->GetStreamPlayer(); + if (!streamPlayer) { + CLOGE("StreamPlayer is null"); + return napi_generic_failure; + } + + auto listener = std::make_shared(); + if (!listener) { + CLOGE("Failed to malloc stream player listener"); + return napi_generic_failure; + } + int32_t ret = streamPlayer->RegisterListener(listener); + if (ret != CAST_ENGINE_SUCCESS) { + CLOGE("native register stream player listener failed"); + return napi_generic_failure; + } + napiStreamPlayer->NapiListenerSetter(listener); + + return napi_ok; +} + +napi_value NapiStreamPlayer::SetSurface(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set surface in"); + struct ConcreteTask : public NapiAsyncTask { + std::string surfaceId_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_string }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->surfaceId_ = ParseString(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->SetSurface(napiAsyntask->surfaceId_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetStreamSurface failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetStreamSurface failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetStreamSurface failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetStreamSurface", executor, complete); +} + +napi_value NapiStreamPlayer::Load(napi_env env, napi_callback_info info) +{ + CLOGD("Start to load in"); + struct ConcreteTask : public NapiAsyncTask { + MediaInfo mediaInfo_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + bool isMediaInfoValid = GetMediaInfoFromJS(env, argv[0], napiAsyntask->mediaInfo_); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isMediaInfoValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Load(napiAsyntask->mediaInfo_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Load failed : no permission"; + } else { + napiAsyntask->errMessage = "Load failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Load", executor, complete); +} + +napi_value NapiStreamPlayer::Start(napi_env env, napi_callback_info info) +{ + CLOGD("Start to start in"); + struct ConcreteTask : public NapiAsyncTask { + MediaInfo mediaInfo_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_object }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + bool isMediaInfoValid = GetMediaInfoFromJS(env, argv[0], napiAsyntask->mediaInfo_); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isMediaInfoValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Play(napiAsyntask->mediaInfo_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Start failed : no permission"; + } else { + napiAsyntask->errMessage = "Start failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Start", executor, complete); +} + +napi_value NapiStreamPlayer::Play(napi_env env, napi_callback_info info) +{ + CLOGD("Start to play in"); + struct ConcreteTask : public NapiAsyncTask { + bool isRemotePlay_ = true; + int index_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedRemotePlayArgc = 0; + constexpr size_t expectedLocalPlayArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedRemotePlayArgc || argc == expectedLocalPlayArgc, + "invalid arguments", NapiErrors::errcode_[ERR_INVALID_PARAM]); + if (argc == expectedLocalPlayArgc) { + napi_valuetype expectedTypes[expectedLocalPlayArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedLocalPlayArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->index_ = ParseInt32(env, argv[0]); + napiAsyntask->isRemotePlay_ = false; + } + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = CAST_ENGINE_ERROR; + if (napiAsyntask->isRemotePlay_) { + ret = streamPlayer->Play(); + } else { + ret = streamPlayer->Play(napiAsyntask->index_); + } + if (ret != CAST_ENGINE_SUCCESS) { + napiAsyntask->errMessage = "Play failed"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Play", executor, complete); +} + +napi_value NapiStreamPlayer::Pause(napi_env env, napi_callback_info info) +{ + CLOGD("Start to pause in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Pause(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Pause failed : no permission"; + } else { + napiAsyntask->errMessage = "Pause failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Pause", executor, complete); +} + +napi_value NapiStreamPlayer::Stop(napi_env env, napi_callback_info info) +{ + CLOGD("Start to stop in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Stop(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Stop failed : no permission"; + } else { + napiAsyntask->errMessage = "Stop failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Stop", executor, complete); +} + +napi_value NapiStreamPlayer::Next(napi_env env, napi_callback_info info) +{ + CLOGD("Start to next in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Next(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Next failed : no permission"; + } else { + napiAsyntask->errMessage = "Next failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Next", executor, complete); +} + +napi_value NapiStreamPlayer::Previous(napi_env env, napi_callback_info info) +{ + CLOGD("Start to previous in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Previous(); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Previous failed : no permission"; + } else { + napiAsyntask->errMessage = "Previous failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Previous", executor, complete); +} + +napi_value NapiStreamPlayer::Seek(napi_env env, napi_callback_info info) +{ + CLOGD("Start to seek in"); + struct ConcreteTask : public NapiAsyncTask { + int position_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->position_ = ParseInt32(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Seek(napiAsyntask->position_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Seek failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "Seek failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "Seek failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Seek", executor, complete); +} + +napi_value NapiStreamPlayer::FastForward(napi_env env, napi_callback_info info) +{ + CLOGD("Start to FastForward in"); + struct ConcreteTask : public NapiAsyncTask { + int delta_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->delta_ = ParseInt32(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->FastForward(napiAsyntask->delta_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "FastForward failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "FastForward failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "FastForward failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "FastForward", executor, complete); +} + +napi_value NapiStreamPlayer::FastRewind(napi_env env, napi_callback_info info) +{ + CLOGD("Start to FastRewind in"); + struct ConcreteTask : public NapiAsyncTask { + int delta_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->delta_ = ParseInt32(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->FastRewind(napiAsyntask->delta_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "FastRewind failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "FastRewind failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "FastRewind failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "FastRewind", executor, complete); +} + +napi_value NapiStreamPlayer::SetVolume(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set volume in"); + struct ConcreteTask : public NapiAsyncTask { + int volume_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->volume_ = ParseInt32(env, argv[0]); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->SetVolume(napiAsyntask->volume_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetVolume failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetVolume failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetVolume failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetVolume", executor, complete); +} + +napi_value NapiStreamPlayer::SetLoopMode(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set loop mode in"); + struct ConcreteTask : public NapiAsyncTask { + LoopMode loopmode_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->loopmode_ = static_cast(ParseInt32(env, argv[0])); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->SetLoopMode(napiAsyntask->loopmode_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetLoopMode failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetLoopMode failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetLoopMode failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetLoopMode", executor, complete); +} + +napi_value NapiStreamPlayer::SetSpeed(napi_env env, napi_callback_info info) +{ + CLOGD("Start to set speed in"); + struct ConcreteTask : public NapiAsyncTask { + PlaybackSpeed speed_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + auto inputParser = [env, napiAsyntask](size_t argc, napi_value *argv) { + constexpr size_t expectedArgc = 1; + CHECK_ARGS_RETURN_VOID(napiAsyntask, argc == expectedArgc, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napi_valuetype expectedTypes[expectedArgc] = { napi_number }; + bool isParamsTypeValid = CheckJSParamsType(env, argv, expectedArgc, expectedTypes); + CHECK_ARGS_RETURN_VOID(napiAsyntask, isParamsTypeValid, "invalid arguments", + NapiErrors::errcode_[ERR_INVALID_PARAM]); + napiAsyntask->speed_ = static_cast(ParseInt32(env, argv[0])); + }; + napiAsyntask->GetJSInfo(env, info, inputParser); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->SetSpeed(napiAsyntask->speed_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "SetSpeed failed : no permission"; + } else if (ret == ERR_INVALID_PARAM) { + napiAsyntask->errMessage = "SetSpeed failed : invalid parameters"; + } else { + napiAsyntask->errMessage = "SetSpeed failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "SetSpeed", executor, complete); +} + +napi_value NapiStreamPlayer::GetPlayerStatus(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get player status in"); + struct ConcreteTask : public NapiAsyncTask { + PlayerStates playerStatus_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetPlayerStatus(napiAsyntask->playerStatus_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetPlayerStatus failed : no permission"; + } else { + napiAsyntask->errMessage = "GetPlayerStatus failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = napi_create_int32(env, static_cast(napiAsyntask->playerStatus_), &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_int32 failed", NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetPlayerStatus", executor, complete); +} + +napi_value NapiStreamPlayer::GetPosition(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get position in"); + struct ConcreteTask : public NapiAsyncTask { + int position_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetPosition(napiAsyntask->position_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetPosition failed : no permission"; + } else { + napiAsyntask->errMessage = "GetPosition failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = napi_create_int32(env, napiAsyntask->position_, &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_int32 failed", NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetPosition", executor, complete); +} + +napi_value NapiStreamPlayer::GetVolume(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get volume in"); + struct ConcreteTask : public NapiAsyncTask { + int volume_; + int maxVolume_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetVolume(napiAsyntask->volume_, napiAsyntask->maxVolume_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetVolume failed : no permission"; + } else { + napiAsyntask->errMessage = "GetVolume failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = napi_create_int32(env, napiAsyntask->volume_, &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_int32 failed", NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetVolume", executor, complete); +} + +napi_value NapiStreamPlayer::GetLoopMode(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get loop mode in"); + struct ConcreteTask : public NapiAsyncTask { + LoopMode loopMode_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetLoopMode(napiAsyntask->loopMode_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetLoopMode failed : no permission"; + } else { + napiAsyntask->errMessage = "GetLoopMode failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = napi_create_int32(env, static_cast(napiAsyntask->loopMode_), &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_int32 failed", NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetLoopMode", executor, complete); +} + +napi_value NapiStreamPlayer::GetPlaySpeed(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get play speed in"); + struct ConcreteTask : public NapiAsyncTask { + PlaybackSpeed speed_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetPlaySpeed(napiAsyntask->speed_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetPlaySpeed failed : no permission"; + } else { + napiAsyntask->errMessage = "GetPlaySpeed failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env, napiAsyntask](napi_value &output) { + napiAsyntask->status = napi_create_int32(env, static_cast(napiAsyntask->speed_), &output); + CHECK_STATUS_RETURN_VOID(napiAsyntask, "napi_create_int32 failed", NapiErrors::errcode_[CAST_ENGINE_ERROR]); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetPlaySpeed", executor, complete); +} + +napi_value NapiStreamPlayer::GetMediaInfoHolder(napi_env env, napi_callback_info info) +{ + CLOGD("Start to get play info holder in"); + struct ConcreteTask : public NapiAsyncTask { + MediaInfoHolder mediaInfoHolder_; + }; + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + + napiAsyntask->GetJSInfo(env, info); + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->GetMediaInfoHolder(napiAsyntask->mediaInfoHolder_); + if (ret != CAST_ENGINE_SUCCESS) { + if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "GetMediaInfoHolder failed : no permission"; + } else { + napiAsyntask->errMessage = "GetMediaInfoHolder failed : native server exception"; + } + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [napiAsyntask](napi_value &output) { + output = ConvertMediaInfoHolderToJS(napiAsyntask->env, napiAsyntask->mediaInfoHolder_); + }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "GetMediaInfoHolder", executor, complete); +} + +napi_value NapiStreamPlayer::Release(napi_env env, napi_callback_info info) +{ + CLOGD("Start to release in"); + auto napiAsyntask = std::make_shared(); + if (napiAsyntask == nullptr) { + CLOGE("Create NapiAsyncTask failed"); + return GetUndefinedValue(env); + } + napiAsyntask->GetJSInfo(env, info); + + auto executor = [napiAsyntask]() { + auto *napiStreamPlayer = reinterpret_cast(napiAsyntask->native); + CHECK_ARGS_RETURN_VOID(napiAsyntask, napiStreamPlayer != nullptr, "napiStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + std::shared_ptr streamPlayer = napiStreamPlayer->GetStreamPlayer(); + CHECK_ARGS_RETURN_VOID(napiAsyntask, streamPlayer, "IStreamPlayer is null", + NapiErrors::errcode_[CAST_ENGINE_ERROR]); + int32_t ret = streamPlayer->Release(); + if (ret == CAST_ENGINE_SUCCESS) { + napiStreamPlayer->Reset(); + } else if (ret == ERR_NO_PERMISSION) { + napiAsyntask->errMessage = "Release failed : no permission"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } else { + napiAsyntask->errMessage = "Release failed : native server exception"; + napiAsyntask->status = napi_generic_failure; + napiAsyntask->errCode = NapiErrors::errcode_[ret]; + } + }; + + auto complete = [env](napi_value &output) { output = GetUndefinedValue(env); }; + return NapiAsyncWork::Enqueue(env, napiAsyntask, "Release", executor, complete); +} + +std::shared_ptr NapiStreamPlayer::NapiListenerGetter() +{ + return listener_; +} + +void NapiStreamPlayer::NapiListenerSetter(std::shared_ptr listener) +{ + listener_ = listener; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/napi_stream_player_listener.cpp b/interfaces/kits/js/src/napi_stream_player_listener.cpp new file mode 100644 index 0000000..c9f767d --- /dev/null +++ b/interfaces/kits/js/src/napi_stream_player_listener.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply stream player listener realization for napi interface. + * Author: huangchanggui + * Create: 2023-1-11 + */ + +#include "napi_stream_player_listener.h" +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "napi_castengine_utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Napi-StreamPlayerListener"); + +NapiStreamPlayerListener::~NapiStreamPlayerListener() +{ + CLOGD("destrcutor in"); + ClearCallback(callback_->GetEnv()); +} + +void NapiStreamPlayerListener::HandleEvent(int32_t event, NapiArgsGetter getter) +{ + std::lock_guard lockGuard(lock_); + if (callbacks_[event].empty()) { + CLOGE("not register callback event=%{public}d", event); + return; + } + for (auto ref = callbacks_[event].begin(); ref != callbacks_[event].end(); ++ref) { + callback_->Call(*ref, getter); + } +} + +void NapiStreamPlayerListener::OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) +{ + CLOGD("OnStateChanged start"); + NapiArgsGetter napiArgsGetter = [playbackState, isPlayWhenReady](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_TWO; + auto status = napi_create_int32(env, static_cast(playbackState), &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_get_boolean(env, isPlayWhenReady, &argv[1]); + CHECK_RETURN_VOID(status == napi_ok, "napi_get_boolean failed"); + }; + HandleEvent(EVENT_PLAYER_STATUS_CHANGED, napiArgsGetter); + CLOGD("OnStateChanged finish"); +} + +void NapiStreamPlayerListener::OnPositionChanged(int position, int bufferPosition, int duration) +{ + CLOGD("OnPositionChanged start"); + std::chrono::steady_clock::duration timestampOrigin = std::chrono::steady_clock::now().time_since_epoch(); + uint64_t timestamp = + static_cast(std::chrono::duration_cast(timestampOrigin).count()); + NapiArgsGetter napiArgsGetter = [position, bufferPosition, duration, timestamp](napi_env env, int &argc, + napi_value *argv) { + argc = CALLBACK_ARGC_FOUR; + auto status = napi_create_int32(env, position, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_int32(env, bufferPosition, &argv[1]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_int32(env, duration, &argv[2]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_bigint_uint64(env, timestamp, &argv[3]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_bigint_uint64 failed"); + }; + HandleEvent(EVENT_POSITION_CHANGED, napiArgsGetter); + CLOGD("OnPositionChanged finish"); +} + +void NapiStreamPlayerListener::OnMediaItemChanged(const MediaInfo &mediaInfo) +{ + CLOGD("OnMediaItemChanged start"); + NapiArgsGetter napiArgsGetter = [mediaInfo](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + argv[0] = ConvertMediaInfoToJS(env, mediaInfo); + }; + HandleEvent(EVENT_MEDIA_ITEM_CHANGED, napiArgsGetter); + CLOGD("OnMediaItemChanged finish"); +} + +void NapiStreamPlayerListener::OnVolumeChanged(int volume, int maxVolume) +{ + CLOGD("OnVolumeChanged start"); + NapiArgsGetter napiArgsGetter = [volume](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + auto status = napi_create_int32(env, volume, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + }; + HandleEvent(EVENT_VOLUME_CHANGED, napiArgsGetter); + CLOGD("OnVolumeChanged finish"); +} + +void NapiStreamPlayerListener::OnVideoSizeChanged(int width, int height) +{ + CLOGD("OnVideoSizeChanged start"); + NapiArgsGetter napiArgsGetter = [width, height](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_TWO; + auto status = napi_create_int32(env, width, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_int32(env, height, &argv[1]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + }; + HandleEvent(EVENT_VIDEO_SIZE_CHANGED, napiArgsGetter); + CLOGD("OnVideoSizeChanged finish"); +} + +void NapiStreamPlayerListener::OnLoopModeChanged(const LoopMode loopMode) +{ + CLOGD("OnLoopModeChanged start"); + NapiArgsGetter napiArgsGetter = [loopMode](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + auto status = napi_create_int32(env, static_cast(loopMode), &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + }; + HandleEvent(EVENT_LOOP_MODE_CHANGED, napiArgsGetter); + CLOGD("OnLoopModeChanged finish"); +} + +void NapiStreamPlayerListener::OnPlaySpeedChanged(const PlaybackSpeed speed) +{ + CLOGD("OnPlaySpeedChanged start"); + NapiArgsGetter napiArgsGetter = [speed](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + auto status = napi_create_int32(env, static_cast(speed), &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_double failed"); + }; + HandleEvent(EVENT_PLAY_SPEED_CHANGED, napiArgsGetter); + CLOGD("OnPlaySpeedChanged finish"); +} + +void NapiStreamPlayerListener::OnPlayerError(int errorCode, const std::string &errorMsg) +{ + CLOGD("OnPlayerError start"); + NapiArgsGetter napiArgsGetter = [errorCode, errorMsg](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_TWO; + auto status = napi_create_int32(env, errorCode, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + status = napi_create_string_utf8(env, errorMsg.c_str(), NAPI_AUTO_LENGTH, &argv[1]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_string_utf8 failed"); + }; + HandleEvent(EVENT_PLAYER_ERROR, napiArgsGetter); + CLOGD("OnPlayerError finish"); +} + +void NapiStreamPlayerListener::OnNextRequest() +{ + CLOGD("OnNextRequest start"); + NapiArgsGetter napiArgsGetter = [](napi_env env, int &argc, napi_value *argv) {}; + HandleEvent(EVENT_NEXT_REQUEST, napiArgsGetter); + CLOGD("OnNextRequest finish"); +} + +void NapiStreamPlayerListener::OnPreviousRequest() +{ + CLOGD("OnPreviousRequest start"); + NapiArgsGetter napiArgsGetter = [](napi_env env, int &argc, napi_value *argv) {}; + HandleEvent(EVENT_PREVIOUS_REQUEST, napiArgsGetter); + CLOGD("OnPreviousRequest finish"); +} + +void NapiStreamPlayerListener::OnSeekDone(int position) +{ + CLOGD("OnSeekDone start"); + NapiArgsGetter napiArgsGetter = [position](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + auto status = napi_create_int32(env, position, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + }; + HandleEvent(EVENT_SEEK_DONE, napiArgsGetter); + CLOGD("OnSeekDone finish"); +} + +void NapiStreamPlayerListener::OnEndOfStream(int isLooping) +{ + CLOGD("OnEndOfStream start"); + NapiArgsGetter napiArgsGetter = [isLooping](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + auto status = napi_create_int32(env, isLooping, &argv[0]); + CHECK_RETURN_VOID(status == napi_ok, "napi_create_int32 failed"); + }; + HandleEvent(EVENT_END_OF_STREAM, napiArgsGetter); + CLOGD("OnEndOfStream finish"); +} + +void NapiStreamPlayerListener::OnPlayRequest(const MediaInfo &mediaInfo) +{ + CLOGD("OnPlayRequest start"); + NapiArgsGetter napiArgsGetter = [mediaInfo](napi_env env, int &argc, napi_value *argv) { + argc = CALLBACK_ARGC_ONE; + argv[0] = ConvertMediaInfoToJS(env, mediaInfo); + }; + HandleEvent(EVENT_PLAY_REQUEST, napiArgsGetter); + CLOGD("OnPlayRequest finish"); +} + +napi_status NapiStreamPlayerListener::AddCallback(napi_env env, int32_t event, napi_value callback) +{ + CLOGI("Add callback %{public}d", event); + constexpr int initialRefCount = 1; + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been registered"); + return napi_ok; + } + napi_status status = napi_create_reference(env, callback, initialRefCount, &ref); + if (status != napi_ok) { + CLOGE("napi_create_reference failed"); + return status; + } + if (callback_ == nullptr) { + callback_ = std::make_shared(env); + if (callback_ == nullptr) { + CLOGE("no memory"); + return napi_generic_failure; + } + } + callbacks_[event].push_back(ref); + return napi_ok; +} + +napi_status NapiStreamPlayerListener::RemoveCallback(napi_env env, int32_t event, napi_value callback) +{ + if (callback == nullptr) { + for (auto &callbackRef : callbacks_[event]) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callbacks_[event].clear(); + return napi_ok; + } + napi_ref ref = nullptr; + if (GetRefByCallback(env, callbacks_[event], callback, ref) != napi_ok) { + CLOGE("get callback reference failed"); + return napi_generic_failure; + } + if (ref != nullptr) { + CLOGD("callback has been remove"); + return napi_ok; + } + callbacks_[event].remove(ref); + return napi_delete_reference(env, ref); +} + +napi_status NapiStreamPlayerListener::ClearCallback(napi_env env) +{ + for (auto &callback : callbacks_) { + for (auto &callbackRef : callback) { + napi_status ret = napi_delete_reference(env, callbackRef); + if (ret != napi_ok) { + CLOGE("delete callback reference failed"); + return ret; + } + } + callback.clear(); + } + + return napi_ok; +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS diff --git a/interfaces/kits/js/src/native_module.cpp b/interfaces/kits/js/src/native_module.cpp new file mode 100644 index 0000000..cde5026 --- /dev/null +++ b/interfaces/kits/js/src/native_module.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: register napi module for napi interfaces. + * Author: zhangjingnan + * Create: 2022-7-11 + */ + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "napi_cast_session_manager.h" +#include "napi_cast_session.h" +#include "napi_castengine_utils.h" +#include "napi_stream_player.h" +#include "napi_mirror_player.h" +#include "napi_castengine_enum.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +EXTERN_C_START + +static napi_value Init(napi_env env, napi_value exports) +{ + InitEnums(env, exports); + NapiCastSessionManager::Init(env, exports); + NapiCastSession::DefineCastSessionJSClass(env); + NapiStreamPlayer::DefineStreamPlayerJSClass(env); + NapiMirrorPlayer::DefineMirrorPlayerJSClass(env); + return exports; +} +EXTERN_C_END + +// module description +static napi_module napiModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "cast", + .nm_priv = ((void *)0), + .reserved = { 0 } +}; + +// module registration +extern "C" __attribute__((constructor)) void RegisterModule() +{ + napi_module_register(&napiModule); +} +} // namespace CastEngineClient +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/patches/patches.json b/patches/patches.json new file mode 100644 index 0000000..db3f759 --- /dev/null +++ b/patches/patches.json @@ -0,0 +1,24 @@ +{ + "patches": [ + { + "project":"vendor_hihope", + "path":"vendor/hihope", + "pr_url":"https://gitee.com/openharmony/vendor_hihope/pulls/970" + }, + { + "project":"build", + "path":"build", + "pr_url":"https://gitee.com/openharmony/build/pulls/2546" + }, + { + "project":"startup_init", + "path":"base/startup/init", + "pr_url":"https://gitee.com/openharmony/startup_init/pulls/2416" + }, + { + "project":"security_selinux_adapter", + "path":"base/security/selinux_adapter", + "pr_url":"https://gitee.com/openharmony/security_selinux_adapter/pulls/3382" + } + ] +} diff --git a/sa_profile/5526.json b/sa_profile/5526.json new file mode 100644 index 0000000..2c27d78 --- /dev/null +++ b/sa_profile/5526.json @@ -0,0 +1,12 @@ +{ + "process": "cast_engine_service", + "systemability": [ + { + "name": 5526, + "libpath": "libcast_engine_service.z.so", + "run-on-create": false, + "distributed": false, + "dump_level": 1 + } + ] +} diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn new file mode 100644 index 0000000..6fb7373 --- /dev/null +++ b/sa_profile/BUILD.gn @@ -0,0 +1,14 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("cast_engine_sa_profile") { + sources = [ "5526.json" ] + part_name = "cast_engine" +} diff --git a/service/BUILD.gn b/service/BUILD.gn new file mode 100644 index 0000000..7d6ea88 --- /dev/null +++ b/service/BUILD.gn @@ -0,0 +1,60 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_service_config") { + include_dirs = [ + "include", + "src/include", + ] +} + +ohos_shared_library("cast_engine_service") { + install_enable = true + sources = [ + "src/cast_service_listener_impl_proxy.cpp", + "src/cast_session_manager_service.cpp", + "src/cast_session_manager_service_stub.cpp", + ] + + configs = [ + ":cast_service_config", + "${cast_engine_root}:cast_engine_default_config", + ] + + deps = [ + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + "src/device_manager:cast_discovery", + "${cast_session_stream_path}:cast_session", + "//third_party/openssl:libcrypto_shared", + ] + + external_deps = [ + "c_utils:utils", + "device_manager:devicemanagersdk", + "dsoftbus:softbus_client", + "graphic_2d:surface", + "hilog:libhilog", + "hisysevent:libhisysevent", + "input:libmmi-client", + "ipc:ipc_core", + "player_framework:media_client", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/service/include/cast_service_listener_impl_proxy.h b/service/include/cast_service_listener_impl_proxy.h new file mode 100644 index 0000000..e74bc8a --- /dev/null +++ b/service/include/cast_service_listener_impl_proxy.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast service listener implement proxy class. + * Author: zhangge + * Create: 2022-6-15 + */ + +#ifndef CAST_SERVICE_LISTENER_IMPL_PROXY_H +#define CAST_SERVICE_LISTENER_IMPL_PROXY_H + +#include "cast_engine_common.h" +#include "i_cast_service_listener_impl.h" +#include "i_cast_session_impl.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +class CastServiceListenerImplProxy : public IRemoteProxy { +public: + explicit CastServiceListenerImplProxy(const sptr &impl) + : IRemoteProxy(impl) + {} + + void OnDeviceFound(const std::vector &deviceList) override; + void OnDeviceOffline(const std::string &deviceId) override; + void OnSessionCreated(const sptr &castSession) override; + void OnServiceDied() override; + +private: + static inline BrokerDelegator delegator_; +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS +#endif \ No newline at end of file diff --git a/service/include/cast_session_manager_service.h b/service/include/cast_session_manager_service.h new file mode 100644 index 0000000..5b61324 --- /dev/null +++ b/service/include/cast_session_manager_service.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast session manager service class + * Author: zhangge + * Create: 2022-06-15 + */ + +#ifndef CAST_SESSION_MANAGER_SERVICE_H +#define CAST_SESSION_MANAGER_SERVICE_H + +#include +#include +#include +#include + +#include "cast_session_manager_service_stub.h" +#include "session.h" +#include "system_ability.h" + +using SharedRLock = std::shared_lock; +using SharedWLock = std::lock_guard; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +class CastSessionManagerService : public SystemAbility, public CastSessionManagerServiceStub { + DECLARE_SYSTEM_ABILITY(CastSessionManagerService); + +public: + CastSessionManagerService(int32_t saId, bool runOnCreate); + ~CastSessionManagerService() override; + + void OnStart() override; + void OnStop() override; + + int32_t RegisterListener(sptr listener) override; + int32_t UnregisterListener() override; + int32_t Release() override; + int32_t SetLocalDevice(const CastLocalDevice &localDevice) override; + int32_t CreateCastSession(const CastSessionProperty &property, sptr &castSession) override; + int32_t SetSinkSessionCapacity(int sessionCapacity) override; + int32_t StartDiscovery(int protocols) override; + int32_t SetDiscoverable(bool enable) override; + int32_t StopDiscovery() override; + void ReleaseServiceResources(pid_t pid); + int32_t GetCastSession(std::string sessionId, sptr &castSession) override; + + bool DestroyCastSession(int32_t sessionId); + void ReportServiceDieLocked(); + void ReportDeviceFound(const std::vector &deviceList); + void ReportSessionCreate(const sptr &castSession); + void ReportDeviceOffline(const std::string &deviceId); + +private: + class CastEngineClientDeathRecipient : public IRemoteObject::DeathRecipient { + public: + CastEngineClientDeathRecipient(wptr service, pid_t pid) + : service_(service), pid_(pid) {}; + void OnRemoteDied(const wptr &object) override; + + private: + wptr service_; + pid_t pid_; + }; + + pid_t myPid_; + std::shared_mutex mutex_; + std::vector>> listeners_; + CastLocalDevice localDevice_{}; + ServiceStatus serviceStatus_{ ServiceStatus::DISCONNECTED }; + int sessionCapacity_{ 0 }; + std::map> sessionMap_; + std::atomic sessionIndex_{ 0 }; + std::unordered_map> deathRecipientMap_; + + void AddClientDeathRecipientLocked(pid_t pid, sptr listener); + void RemoveClientDeathRecipientLocked(pid_t pid, sptr listener); + bool AddListenerLocked(sptr listener); + int32_t ReleaseLocked(); + int32_t RemoveListenerLocked(pid_t pid); + void ClearListenersLocked(); + bool HasListenerLocked(); +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/service/include/cast_session_manager_service_stub.h b/service/include/cast_session_manager_service_stub.h new file mode 100644 index 0000000..9a6fda2 --- /dev/null +++ b/service/include/cast_session_manager_service_stub.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast session manager service stub class. + * Author: zhangge + * Create: 2022-5-29 + */ + +#ifndef CAST_SESSION_MANAGER_SERVICE_STUB_H +#define CAST_SESSION_MANAGER_SERVICE_STUB_H + +#include "cast_stub_helper.h" +#include "i_cast_session_manager_service.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +class CastSessionManagerServiceStub : public IRemoteStub { +public: + CastSessionManagerServiceStub(); + ~CastSessionManagerServiceStub() override; + + int OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; + +private: + DECLARE_STUB_TASK_MAP(CastSessionManagerServiceStub); + + int32_t DoRegisterListenerTask(MessageParcel &data, MessageParcel &reply); + int32_t DoUnregisterListenerTask(MessageParcel &data, MessageParcel &reply); + int32_t DoReleaseTask(MessageParcel &data, MessageParcel &reply); + int32_t DoSetLocalDeviceTask(MessageParcel &data, MessageParcel &reply); + int32_t DoCreateCastSessionTask(MessageParcel &data, MessageParcel &reply); + int32_t DoSetSinkSessionCapacityTask(MessageParcel &data, MessageParcel &reply); + int32_t DoStartDiscoveryTask(MessageParcel &data, MessageParcel &reply); + int32_t DoSetDiscoverableTask(MessageParcel &data, MessageParcel &reply); + int32_t DoStopDiscoveryTask(MessageParcel &data, MessageParcel &reply); + int32_t DoGetCastSessionTask(MessageParcel &data, MessageParcel &reply); +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + + +#endif // CAST_SESSION_MANAGER_SERVICE_STUB_H \ No newline at end of file diff --git a/service/src/cast_service_listener_impl_proxy.cpp b/service/src/cast_service_listener_impl_proxy.cpp new file mode 100644 index 0000000..7507431 --- /dev/null +++ b/service/src/cast_service_listener_impl_proxy.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast service listener implement proxy class. + * Author: zhangge + * Create: 2022-6-15 + */ + +#include "cast_service_listener_impl_proxy.h" + +#include +#include "cast_engine_log.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Service-ListenerImpl"); + +void CastServiceListenerImplProxy::OnServiceDied() +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return; + } + if (Remote()->SendRequest(ON_SERVICE_DIE, data, reply, option) != ERR_NONE) { + CLOGE("Failed to send ipc request when reporting service die"); + } +} + +namespace { +bool FillCastRemoteDevices(MessageParcel &data, const std::vector &devices) +{ + auto size = devices.size(); + if (size <= 0) { + CLOGE("devices size <= 0"); + return false; + } + if (!data.WriteInt32(static_cast(size))) { + CLOGE("Failed to write the device size:%u", size); + return false; + } + for (auto &device : devices) { + if (!WriteCastRemoteDevice(data, device)) { + CLOGE("Failed to write the remote device item"); + return false; + } + } + return true; +} + +bool FillCastSession(MessageParcel &data, const sptr &castSession) +{ + if (!castSession) { + return false; + } + if (!data.WriteRemoteObject(castSession->AsObject())) { + CLOGE("Failed to write cast session"); + return false; + } + return true; +} +} // namespace + +void CastServiceListenerImplProxy::OnDeviceFound(const std::vector &devices) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return; + } + if (!FillCastRemoteDevices(data, devices)) { + CLOGE("Failed to Write remote devices"); + return; + } + Remote()->SendRequest(ON_DEVICE_FOUND, data, reply, option); +} + +void CastServiceListenerImplProxy::OnSessionCreated(const sptr &castSession) +{ + MessageParcel data, reply; + MessageOption option; + + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return; + } + if (!FillCastSession(data, castSession)) { + CLOGE("Failed to Write cast session"); + return; + } + Remote()->SendRequest(ON_SESSION_CREATE, data, reply, option); +} + +void CastServiceListenerImplProxy::OnDeviceOffline(const std::string &deviceId) +{ + MessageParcel data, reply; + MessageOption option; + CLOGD("OnDeviceOffline in"); + if (!data.WriteInterfaceToken(GetDescriptor())) { + CLOGE("Failed to write the interface token"); + return; + } + if (!data.WriteString(deviceId)) { + CLOGE("Failed to Write deviceId"); + return; + } + CLOGD("send request"); + Remote()->SendRequest(ON_DEVICE_OFFLINE, data, reply, option); +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS \ No newline at end of file diff --git a/service/src/cast_session_manager_service.cpp b/service/src/cast_session_manager_service.cpp new file mode 100644 index 0000000..b331d24 --- /dev/null +++ b/service/src/cast_session_manager_service.cpp @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast session manager service class + * Author: zhangge + * Create: 2022-06-15 + */ + +#include "cast_session_manager_service.h" + +#include +#include + +#include +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "cast_engine_dfx.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_session_impl.h" +#include "connection_manager.h" +#include "discovery_manager.h" +#include "hisysevent.h" +#include "permission.h" +#include "utils.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Service"); + +REGISTER_SYSTEM_ABILITY_BY_ID(CastSessionManagerService, CAST_ENGINE_SA_ID, false); + +CastSessionManagerService::CastSessionManagerService(int32_t saId, bool runOnCreate) : SystemAbility(saId, runOnCreate) +{ + CLOGD("construction in"); + myPid_ = getpid(); +}; + +CastSessionManagerService::~CastSessionManagerService() +{ + CLOGD("destruction in"); +} + +void CastSessionManagerService::OnStart() +{ + bool ret = Publish(this); + if (!ret) { + CLOGE("Failed to publish cast session manager service"); + return; + } + + AddSystemAbilityListener(CAST_ENGINE_SA_ID); +} + +void CastSessionManagerService::OnStop() {} + +namespace { +using namespace OHOS::DistributedHardware; + +class DiscoveryManagerListener : public IDiscoveryManagerListener { +public: + DiscoveryManagerListener(sptr service) : service_(service) {} + + void OnDeviceFound(const std::vector &devices) override + { + auto service = service_.promote(); + if (!service) { + CLOGE("service is null"); + return; + } + + std::vector remoteDevices; + for (const auto &device : devices) { + remoteDevices.push_back(CastRemoteDevice{ device.deviceId, device.deviceName, device.deviceType, + device.subDeviceType, device.ipAddress, device.channelType }); + } + service->ReportDeviceFound(remoteDevices); + } + +private: + wptr service_; +}; + +class ConnectionManagerListener : public IConnectionManagerListener { +public: + ConnectionManagerListener(sptr service) : service_(service) {} + + int NotifySessionIsReady() override + { + auto service = service_.promote(); + if (!service) { + CLOGE("service is null"); + return INVALID_ID; + } + + sptr session; + service->CreateCastSession({}, session); + if (session == nullptr) { + return INVALID_ID; + } + + service->ReportSessionCreate(session); + std::string sessionId{}; + session->GetSessionId(sessionId); + return Utils::StringToInt((sessionId)); + } + + bool NotifyRemoteDeviceIsReady(int castSessionId, const CastInnerRemoteDevice &device) override + { + auto service = service_.promote(); + if (!service) { + CLOGE("service is null"); + return INVALID_ID; + } + sptr session; + service->GetCastSession(std::to_string(castSessionId), session); + if (session == nullptr) { + CLOGE("Session is null when consultation data comes!"); + return false; + } + return session->AddDevice(device); + } + + void NotifyDeviceIsOffline(const std::string &deviceId) override + { + auto service = service_.promote(); + if (!service) { + CLOGE("service is null"); + return; + } + service->ReportDeviceOffline(deviceId); + CLOGD("OnDeviceOffline out"); + } + + void OnError(const std::string &deviceId) override + { + auto service = service_.promote(); + if (!service) { + CLOGE("service is null"); + return; + } + int sessionId = CastDeviceDataManager::GetInstance().GetSessionIdByDeviceId(deviceId); + if (sessionId == INVALID_ID) { + CLOGE("The obtained sessionId is null"); + return; + } + sptr session; + service->GetCastSession(std::to_string(sessionId), session); + if (!session) { + CLOGE("The session is null. Failed to obtain the session."); + return; + } + session->RemoveDevice(deviceId); + } + +private: + wptr service_; +}; +} // namespace + +int32_t CastSessionManagerService::RegisterListener(sptr listener) +{ + CLOGI("RegisterListener in"); + HiSysEventWrite(CAST_ENGINE_DFX_DOMAIN_NAME, "CAST_ENGINE_EVE", HiviewDFX::HiSysEvent::EventType::STATISTIC, + "SEQUENTIAL_ID", CastEngineDfx::GetSequentialId(), "BIZ_PACKAGE_NAME", CastEngineDfx::GetBizPackageName()); + SharedWLock lock(mutex_); + if (listener == nullptr) { + CLOGE("RegisterListener failed, listener is null"); + return CAST_ENGINE_ERROR; + } + bool needInitMore = !HasListenerLocked(); + if (!AddListenerLocked(listener)) { + return CAST_ENGINE_ERROR; + } + + if (needInitMore) { + DiscoveryManager::GetInstance().Init(std::make_shared(this)); + ConnectionManager::GetInstance().Init(std::make_shared(this)); + sessionMap_.clear(); + } + + serviceStatus_ = ServiceStatus::CONNECTED; + CLOGI("RegisterListener out"); + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::UnregisterListener() +{ + SharedWLock lock(mutex_); + CLOGI("UnregisterListener in"); + + return RemoveListenerLocked(IPCSkeleton::GetCallingPid()); +} + +int32_t CastSessionManagerService::Release() +{ + SharedWLock lock(mutex_); + CLOGI("Release in"); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + + return ReleaseLocked(); +} + +int32_t CastSessionManagerService::ReleaseLocked() +{ + CLOGI("ReleaseLocked in"); + serviceStatus_ = ServiceStatus::DISCONNECTED; + ReportServiceDieLocked(); + + ClearListenersLocked(); + DiscoveryManager::GetInstance().Deinit(); + ConnectionManager::GetInstance().Deinit(); + sessionMap_.clear(); + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + CLOGE("get samgr failed"); + return CAST_ENGINE_ERROR; + } + int32_t ret = samgr->UnloadSystemAbility(CAST_ENGINE_SA_ID); + if (ret != ERR_OK) { + CLOGE("remove system ability failed"); + return CAST_ENGINE_ERROR; + } + CLOGI("Release success done"); + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::SetLocalDevice(const CastLocalDevice &localDevice) +{ + CLOGD("SetLocalDevice in"); + SharedWLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + localDevice_ = localDevice; + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::GetCastSession(std::string sessionId, sptr &castSession) +{ + auto innerSessionId = Utils::StringToInt(sessionId); + SharedRLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + + auto it = sessionMap_.find(innerSessionId); + if (it == sessionMap_.end()) { + CLOGE("No sessionId=%{public}d session.", innerSessionId); + return ERR_SESSION_NOT_EXIST; + } + + castSession = it->second; + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::CreateCastSession(const CastSessionProperty &property, + sptr &castSession) +{ + SharedWLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + CLOGD("CreateCastSession in, protocol:%{public}d, endType:%{public}d.", property.protocolType, property.endType); + if (serviceStatus_ != ServiceStatus::CONNECTED) { + CLOGE("not connected"); + return ERR_SERVICE_STATE_NOT_MATCH; + } + + if (localDevice_.deviceId.empty()) { + auto local = ConnectionManager::GetInstance().GetLocalDeviceInfo(); + if (local == nullptr) { + return CAST_ENGINE_ERROR; + } + localDevice_ = *local; + } + + auto tmp = new (std::nothrow) CastSessionImpl(property, localDevice_); + if (tmp == nullptr) { + CLOGE("CastSessionImpl is null"); + return ERR_NO_MEMORY; + } + sptr session(static_cast(tmp)); + tmp->Init(); + tmp->SetServiceCallbackForRelease([this](int32_t sessionId) { DestroyCastSession(sessionId); }); + + sessionIndex_++; + std::string sessionId{}; + session->GetSessionId(sessionId); + sessionMap_.insert({ Utils::StringToInt(sessionId), session }); + + CLOGD("CreateCastSession success, session(%{public}d) count:%{public}zu", + Utils::StringToInt(sessionId), sessionMap_.size()); + castSession = session; + return CAST_ENGINE_SUCCESS; +} + +bool CastSessionManagerService::DestroyCastSession(int32_t sessionId) +{ + CLOGD("DestroyCastSession in"); + sptr session; + { + SharedWLock lock(mutex_); + auto it = sessionMap_.find(sessionId); + if (it == sessionMap_.end()) { + CLOGE("Cast session(%d) has gone.", sessionId); + return true; + } + session = it->second; + sessionMap_.erase(it); + } + + session->Stop(); + CLOGD("Session refcount is %d, session count:%zu", session->GetSptrRefCount(), sessionMap_.size()); + return true; +} + +int32_t CastSessionManagerService::SetSinkSessionCapacity(int sessionCapacity) +{ + CLOGD("SetSinkSessionCapacity in, sessionCapacity = %d", sessionCapacity); + SharedRLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + sessionCapacity_ = sessionCapacity; + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::StartDiscovery(int protocols) +{ + static_cast(protocols); + CLOGD("StartDiscovery in, protocolType = %d", protocols); + SharedRLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + DiscoveryManager::GetInstance().StartDiscovery(); + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::StopDiscovery() +{ + CLOGD("StopDiscovery in"); + SharedRLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + DiscoveryManager::GetInstance().StopDiscovery(); + return CAST_ENGINE_SUCCESS; +} + +int32_t CastSessionManagerService::SetDiscoverable(bool enable) +{ + CLOGD("SetDiscoverable in, enable = %{public}d", enable); + SharedRLock lock(mutex_); + if (!Permission::CheckPidPermission()) { + return ERR_NO_PERMISSION; + } + bool ret = false; + if (enable) { + ret = ConnectionManager::GetInstance().EnableDiscoverable(); + } else { + ret = ConnectionManager::GetInstance().DisableDiscoverable(); + } + + return ret ? CAST_ENGINE_SUCCESS : CAST_ENGINE_ERROR; +} + +void CastSessionManagerService::ReleaseServiceResources(pid_t pid) +{ + { + SharedWLock lock(mutex_); + RemoveListenerLocked(pid); + for (auto it = sessionMap_.begin(); it != sessionMap_.end();) { + if (it->second->ReleaseSessionResources(pid)) { + sessionMap_.erase(it++); + continue; + } + it++; + } + if (HasListenerLocked()) { + return; + } + } + CLOGD("Release service resources"); + if (Release() != CAST_ENGINE_SUCCESS) { + CLOGE("Release service resources failed"); + } +} + +void CastSessionManagerService::AddClientDeathRecipientLocked(pid_t pid, sptr listener) +{ + sptr deathRecipient( + new (std::nothrow) CastEngineClientDeathRecipient(wptr(this), pid)); + if (deathRecipient == nullptr) { + CLOGE("Alloc death recipient filed"); + return; + } + if (!listener->AsObject()->AddDeathRecipient(deathRecipient)) { + CLOGE("Add cast client death recipient failed"); + return; + } + CLOGD("add death recipient pid:%d", pid); + deathRecipientMap_[pid] = deathRecipient; +} + +void CastSessionManagerService::RemoveClientDeathRecipientLocked(pid_t pid, sptr listener) +{ + auto it = deathRecipientMap_.find(pid); + if (it != deathRecipientMap_.end()) { + listener->AsObject()->RemoveDeathRecipient(it->second); + deathRecipientMap_.erase(it); + CLOGD("remove death recipient pid:%d", pid); + } +} + +bool CastSessionManagerService::AddListenerLocked(sptr listener) +{ + pid_t pid = IPCSkeleton::GetCallingPid(); + Permission::SavePid(pid); + if (std::find_if(listeners_.begin(), listeners_.end(), + [pid](std::pair> member) { return member.first == pid; }) == + listeners_.end()) { + listeners_.push_back({ pid, listener }); + AddClientDeathRecipientLocked(pid, listener); + return true; + } + + CLOGE("The process(%u) has register the listener", pid); + return false; +} + +int32_t CastSessionManagerService::RemoveListenerLocked(pid_t pid) +{ + Permission::RemovePid(pid); + auto iter = std::find_if(listeners_.begin(), listeners_.end(), + [pid](std::pair> element) { return element.first == pid; }); + if (iter != listeners_.end()) { + RemoveClientDeathRecipientLocked(pid, (*iter).second); + listeners_.erase(iter); + if (listeners_.size() == 0) { + ReleaseLocked(); + } + return CAST_ENGINE_SUCCESS; + } + return CAST_ENGINE_ERROR; +} + +void CastSessionManagerService::ClearListenersLocked() +{ + listeners_.clear(); + Permission::ClearPids(); +} + +bool CastSessionManagerService::HasListenerLocked() +{ + return listeners_.size() > 0; +} + +void CastSessionManagerService::ReportServiceDieLocked() +{ + pid_t pid = IPCSkeleton::GetCallingPid(); + if (pid == myPid_) { + for (const auto &listener : listeners_) { + listener.second->OnServiceDied(); + } + return; + } + + auto it = std::find_if(listeners_.begin(), listeners_.end(), + [pid](std::pair> element) { return element.first == pid; }); + if (it != listeners_.end()) { + it->second->OnServiceDied(); + return; + } +} + +void CastSessionManagerService::ReportDeviceFound(const std::vector &deviceList) +{ + SharedRLock lock(mutex_); + for (const auto &listener : listeners_) { + listener.second->OnDeviceFound(deviceList); + } +} + +void CastSessionManagerService::ReportSessionCreate(const sptr &castSession) +{ + SharedRLock lock(mutex_); + for (const auto &listener : listeners_) { + listener.second->OnSessionCreated(castSession); + } +} + +void CastSessionManagerService::ReportDeviceOffline(const std::string &deviceId) +{ + SharedRLock lock(mutex_); + for (const auto &listener : listeners_) { + listener.second->OnDeviceOffline(deviceId); + } +} + +void CastSessionManagerService::CastEngineClientDeathRecipient::OnRemoteDied(const wptr &object) +{ + CLOGD("Client died, need release resources, client pid_: %d", pid_); + sptr service = service_.promote(); + if (service == nullptr) { + CLOGE("ServiceStub is nullptr"); + return; + } + service->ReleaseServiceResources(pid_); +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS diff --git a/service/src/cast_session_manager_service_stub.cpp b/service/src/cast_session_manager_service_stub.cpp new file mode 100644 index 0000000..78ea1d8 --- /dev/null +++ b/service/src/cast_session_manager_service_stub.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: supply cast session manager service stub class. + * Author: zhangge + * Create: 2022-5-29 + */ + +#include "cast_session_manager_service_stub.h" + +#include "cast_engine_common_helper.h" +#include "cast_engine_log.h" +#include "cast_service_listener_impl_proxy.h" +#include "permission.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Service"); + +int CastSessionManagerServiceStub::OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) +{ + RETRUEN_IF_WRONG_TASK(code, data, reply, option); + return EXECUTE_SINGLE_STUB_TASK(code, data, reply); +} + +CastSessionManagerServiceStub::CastSessionManagerServiceStub() +{ + FILL_SINGLE_STUB_TASK(REGISTER_LISTENER, &CastSessionManagerServiceStub::DoRegisterListenerTask); + FILL_SINGLE_STUB_TASK(UNREGISTER_LISTENER, &CastSessionManagerServiceStub::DoUnregisterListenerTask); + FILL_SINGLE_STUB_TASK(RELEASE, &CastSessionManagerServiceStub::DoReleaseTask); + FILL_SINGLE_STUB_TASK(SET_LOCAL_DEVICE, &CastSessionManagerServiceStub::DoSetLocalDeviceTask); + FILL_SINGLE_STUB_TASK(CREATE_CAST_SESSION, &CastSessionManagerServiceStub::DoCreateCastSessionTask); + FILL_SINGLE_STUB_TASK(SET_SINK_SESSION_CAPACITY, &CastSessionManagerServiceStub::DoSetSinkSessionCapacityTask); + FILL_SINGLE_STUB_TASK(START_DISCOVERY, &CastSessionManagerServiceStub::DoStartDiscoveryTask); + FILL_SINGLE_STUB_TASK(SET_DISCOVERABLE, &CastSessionManagerServiceStub::DoSetDiscoverableTask); + FILL_SINGLE_STUB_TASK(STOP_DISCOVERY, &CastSessionManagerServiceStub::DoStopDiscoveryTask); + FILL_SINGLE_STUB_TASK(GET_CAST_SESSION, &CastSessionManagerServiceStub::DoGetCastSessionTask); +} + +CastSessionManagerServiceStub::~CastSessionManagerServiceStub() +{ + CLOGD("destructor in"); +} + +int32_t CastSessionManagerServiceStub::DoRegisterListenerTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission() && + !Permission::CheckPidPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + sptr obj = data.ReadRemoteObject(); + if (obj == nullptr) { + return ERR_NULL_OBJECT; + } + + sptr listener{ new (std::nothrow) CastServiceListenerImplProxy(obj) }; + if (listener == nullptr) { + CLOGE("RegisterListener failed, listener is null"); + } + + if (!reply.WriteInt32(RegisterListener(listener))) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoUnregisterListenerTask(MessageParcel &data, MessageParcel &reply) +{ + if (!reply.WriteInt32(UnregisterListener())) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoReleaseTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(data); + + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + if (!reply.WriteInt32(Release())) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoSetLocalDeviceTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + auto device = ReadCastLocalDevice(data); + if (device == nullptr) { + CLOGE("Invalid device object comes"); + return ERR_INVALID_DATA; + } + + if (!reply.WriteInt32(SetLocalDevice(*device))) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoCreateCastSessionTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + auto property = ReadCastSessionProperty(data); + if (property == nullptr) { + CLOGE("Invalid property object comes"); + return ERR_INVALID_DATA; + } + + sptr sessionStub; + int32_t ret = CreateCastSession(*property, sessionStub); + if (sessionStub == nullptr) { + return IPC_STUB_ERR; + } + if (!reply.WriteInt32(ret)) { + CLOGE("Failed to write ret:%d", ret); + return IPC_STUB_WRITE_PARCEL_ERR; + } + if (!reply.WriteRemoteObject(sessionStub->AsObject())) { + CLOGE("Failed to write cast session"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoSetSinkSessionCapacityTask(MessageParcel &data, MessageParcel &reply) +{ + static_cast(reply); + + if (!Permission::CheckMirrorPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + int32_t capacity = data.ReadInt32(); + int32_t ret = SetSinkSessionCapacity(capacity); + if (!reply.WriteInt32(ret)) { + CLOGE("Failed to write ret:%d", ret); + return IPC_STUB_WRITE_PARCEL_ERR; + } + + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoStartDiscoveryTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + int32_t type = data.ReadInt32(); + if (!IsProtocolType(type)) { + CLOGE("Invalid protocol type comes, %{public}d", type); + return ERR_INVALID_DATA; + } + if (!reply.WriteInt32(StartDiscovery(type))) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoSetDiscoverableTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + bool enable = data.ReadBool(); + if (!reply.WriteInt32(SetDiscoverable(enable))) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoStopDiscoveryTask(MessageParcel &data, MessageParcel &reply) +{ + if (!Permission::CheckMirrorPermission() && !Permission::CheckStreamPermission()) { + return ERR_UNKNOWN_TRANSACTION; + } + + if (!reply.WriteInt32(StopDiscovery())) { + CLOGE("Failed to write int value"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return ERR_NONE; +} + +int32_t CastSessionManagerServiceStub::DoGetCastSessionTask(MessageParcel &data, MessageParcel &reply) +{ + sptr sessionStub; + int32_t ret = GetCastSession(data.ReadString(), sessionStub); + if (sessionStub == nullptr) { + return IPC_STUB_ERR; + } + if (!reply.WriteInt32(ret)) { + CLOGE("Failed to write ret:%d", ret); + return IPC_STUB_WRITE_PARCEL_ERR; + } + if (!reply.WriteRemoteObject(sessionStub->AsObject())) { + CLOGE("Failed to write cast session"); + return IPC_STUB_WRITE_PARCEL_ERR; + } + return ERR_NONE; +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS diff --git a/service/src/device_manager/BUILD.gn b/service/src/device_manager/BUILD.gn new file mode 100644 index 0000000..dc24330 --- /dev/null +++ b/service/src/device_manager/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_discovery_config") { + include_dirs = [ "include" ] +} + +ohos_static_library("cast_discovery") { + sources = [ + "src/cast_device_data_manager.cpp", + "src/connection_manager.cpp", + "src/discovery_manager.cpp", + ] + + configs = [ + ":cast_discovery_config", + "${cast_engine_root}:cast_engine_default_config", + ] + + include_dirs = [ + "${cast_engine_interfaces}/inner_api/include", + "//third_party/json/single_include/nlohmann", + ] + + public_configs = [ ":cast_discovery_config" ] + + deps = [ "${cast_engine_common}:cast_engine_common_sources" ] + + external_deps = [ + "c_utils:utils", + "device_manager:devicemanagersdk", + "dsoftbus:softbus_client", + "hilog:libhilog", + "hisysevent:libhisysevent", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} diff --git a/service/src/device_manager/include/cast_device_data_manager.h b/service/src/device_manager/include/cast_device_data_manager.h new file mode 100644 index 0000000..515f6a1 --- /dev/null +++ b/service/src/device_manager/include/cast_device_data_manager.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast device data management + * Author: zhangge + * Create: 2022-10-15 + */ + +#ifndef CAST_DEVICE_DATA_MANAGE_H +#define CAST_DEVICE_DATA_MANAGE_H + +#include +#include +#include +#include +#include + +#include "cast_service_common.h" +#include "device_manager.h" + +using OHOS::DistributedHardware::DmDeviceInfo; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +enum class RemoteDeviceState { + UNKNOWN, + FOUND, + CONNECTING, + CONNECTED, +}; + +class CastDeviceDataManager final { +public: + static CastDeviceDataManager &GetInstance(); + + ~CastDeviceDataManager() = default; + + bool AddDevice(const CastInnerRemoteDevice &device, const DmDeviceInfo &dmDeviceInfo); + bool HasDevice(const std::string &deviceId); + bool UpdateDevice(const CastInnerRemoteDevice &device); + void RemoveDevice(const std::string &deviceId); + + std::optional GetDeviceByDeviceId(const std::string &deviceId); + std::optional GetDeviceByTransId(int sessionId); + std::optional GetDmDevice(const std::string &deviceId); + + bool SetDeviceTransId(const std::string &deviceId, int transportId); + int GetDeviceTransId(const std::string &deviceId); + int ResetDeviceTransId(const std::string &deviceId); + + bool SetDeviceRole(const std::string &deviceId, bool isSink); + std::optional GetDeviceRole(const std::string &deviceId); + + bool SetDeviceNetworkId(const std::string &deviceId, const std::string &networkId); + std::optional GetDeviceNetworkId(const std::string &deviceId); + + bool SetDeviceIsActiveAuth(const std::string &deviceId, bool isActiveAuth); + std::optional GetDeviceIsActiveAuth(const std::string &deviceId); + + bool SetDeviceState(const std::string &deviceId, RemoteDeviceState state); + RemoteDeviceState GetDeviceState(const std::string &deviceId); + bool IsDeviceConnected(const std::string &deviceId); + bool IsDeviceConnecting(const std::string &deviceId); + bool IsDeviceUsed(const std::string &deviceId); + int GetSessionIdByDeviceId(const std::string &deviceId); + +private: + struct DeviceInfoCollection { + CastInnerRemoteDevice device; + DmDeviceInfo dmDeviceInfo; + RemoteDeviceState state{ RemoteDeviceState::UNKNOWN }; + std::string networkId; + int localSessionId{ INVALID_ID }; + int transportId{ INVALID_ID }; + bool isActiveAuth{ false }; + bool isSink{ false }; + }; + + CastDeviceDataManager() = default; + + std::vector::iterator GetDeviceLocked(const std::string &deviceId); + void RemoveDeivceLocked(const std::string &deviceId); + RemoteDeviceState GetDeviceStateLocked(const std::string &deviceId); + bool HasDeviceLocked(const std::string &deviceId); + + std::mutex mutex_; + std::vector devices_; +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/service/src/device_manager/include/connection_manager.h b/service/src/device_manager/include/connection_manager.h new file mode 100644 index 0000000..14233f1 --- /dev/null +++ b/service/src/device_manager/include/connection_manager.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: implement the cast source connect + * Author: zhangge + * Create: 2022-08-23 + */ + +#ifndef CONNECTION_MANAGER_H +#define CONNECTION_MANAGER_H + +#include +#include +#include +#include + +#include "cast_device_data_manager.h" +#include "cast_engine_common.h" +#include "cast_engine_log.h" +#include "cast_service_common.h" +#include "device_manager.h" +#include "session.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +using OHOS::DistributedHardware::AuthenticateCallback; +using OHOS::DistributedHardware::DeviceStateCallback; +using OHOS::DistributedHardware::DmDeviceInfo; + +class CastAuthenticateCallback : public AuthenticateCallback { +public: + void OnAuthResult(const std::string &deviceId, const std::string &token, int32_t status, int32_t reason) override; +}; + +class IConnectionManagerListener { +public: + IConnectionManagerListener() = default; + virtual ~IConnectionManagerListener() = default; + + virtual int NotifySessionIsReady() = 0; + virtual void NotifyDeviceIsOffline(const std::string &deviceId) = 0; + virtual bool NotifyRemoteDeviceIsReady(int castSessionId, const CastInnerRemoteDevice &device) = 0; + virtual void OnError(const std::string &deviceId) = 0; +}; + +class ConnectionManager { +public: + static ConnectionManager &GetInstance(); + + void Init(std::shared_ptr listener); + void Deinit(); + + bool IsDeviceTrusted(const std::string &deviceId, std::string &networkId); + bool EnableDiscoverable(); + bool DisableDiscoverable(); + + bool OpenConsultSession(const std::string &deviceId); + void OnConsultDataReceived(int transportId, const void *data, unsigned int dataLen); + void OnConsultSessionOpened(int transportId, bool isSource); + + bool ConnectDevice(const CastInnerRemoteDevice &dev); + void DisconnectDevice(const std::string &deviceId); + + bool UpdateDeviceState(const std::string &deviceId, RemoteDeviceState state); + + std::unique_ptr GetLocalDeviceInfo(); + void NotifySessionIsReady(int transportId); + void NotifyDeviceIsOffline(const std::string &deviceId); + void ReportErrorByListener(const std::string &deviceId); + +private: + bool AuthenticateDevice(const std::string &deviceId); + void SendConsultData(const CastInnerRemoteDevice &device); + void DestroyConsulationSession(const std::string &deviceId); + int GetCastSessionId(int transportId); + std::unique_ptr GetRemoteFromJsonData(const std::string &Data); + + void SetListener(std::shared_ptr listener); + bool HasListener(); + void ResetListener(); + + std::mutex mutex_; + std::shared_ptr listener_; + std::map transIdToCastSessionIdMap_; + bool isDiscoverable_{ false }; +}; + +class CastDeviceStateCallback : public DeviceStateCallback { +public: + void OnDeviceOnline(const DmDeviceInfo &deviceInfo) override; + void OnDeviceOffline(const DmDeviceInfo &deviceInfo) override; + void OnDeviceChanged(const DmDeviceInfo &deviceInfo) override; + void OnDeviceReady(const DmDeviceInfo &deviceInfo) override; +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + +#endif // CONNECTION_MANAGER_H \ No newline at end of file diff --git a/service/src/device_manager/include/discovery_manager.h b/service/src/device_manager/include/discovery_manager.h new file mode 100644 index 0000000..85e83ef --- /dev/null +++ b/service/src/device_manager/include/discovery_manager.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: define cast source discovery. + * Author: zhangge + * Create: 2022-08-06 + */ + +#ifndef DISCOVERY_MANAGER_H +#define DISCOVERY_MANAGER_H + +#include +#include +#include + +#include "cast_engine_common.h" +#include "cast_service_common.h" +#include "device_manager.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +using OHOS::DistributedHardware::DiscoveryCallback; +using OHOS::DistributedHardware::DmDeviceInfo; +using OHOS::DistributedHardware::DmInitCallback; + +class CastDmInitCallback : public DmInitCallback { +public: + void OnRemoteDied() override; +}; + +class IDiscoveryManagerListener { +public: + IDiscoveryManagerListener() = default; + IDiscoveryManagerListener(const IDiscoveryManagerListener &) = delete; + IDiscoveryManagerListener &operator=(const IDiscoveryManagerListener &) = delete; + IDiscoveryManagerListener(IDiscoveryManagerListener &&) = delete; + IDiscoveryManagerListener &operator=(IDiscoveryManagerListener &&) = delete; + virtual ~IDiscoveryManagerListener() = default; + + virtual void OnDeviceFound(const std::vector &devices) = 0; +}; + +class CastDiscoveryCallback : public DiscoveryCallback { +public: + virtual void OnDiscoverySuccess(uint16_t subscribeId) override; + virtual void OnDiscoveryFailed(uint16_t subscribeId, int32_t failedReason) override; + virtual void OnDeviceFound(uint16_t subscribeId, const DmDeviceInfo &deviceInfo) override; +}; + +class DiscoveryManager { +public: + static DiscoveryManager &GetInstance(); + + void Init(std::shared_ptr listener); + void Deinit(); + + void StartDiscovery(); + void StopDiscovery(); + + void OnDeviceInfoFound(uint16_t subscribeId, const DmDeviceInfo &dmDeviceInfo); + void NotifyDeviceIsFound(const std::vector &dmDevices, bool isTrusted, bool isOnline); + +private: + void StartDmDiscovery(); + void GetAndReportTrustedDevices(); + + void SetListener(std::shared_ptr listener); + bool HasListener(); + void ResetListener(); + + std::mutex mutex_; + std::shared_ptr listener_; +}; +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS +#endif // DISCOVERY_MANAGER_H diff --git a/service/src/device_manager/src/cast_device_data_manager.cpp b/service/src/device_manager/src/cast_device_data_manager.cpp new file mode 100644 index 0000000..0c9610a --- /dev/null +++ b/service/src/device_manager/src/cast_device_data_manager.cpp @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: cast device data management + * Author: zhangge + * Create: 2022-10-15 + */ + +#include "cast_device_data_manager.h" + +#include "cast_engine_log.h" +#include "cast_service_common.h" +#include "securec.h" + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-DeviceDataManager"); + +CastDeviceDataManager &CastDeviceDataManager::GetInstance() +{ + static CastDeviceDataManager manager{}; + return manager; +} + +bool CastDeviceDataManager::AddDevice(const CastInnerRemoteDevice &device, const DmDeviceInfo &dmDeviceInfo) +{ + if (device.deviceId.empty() || device.deviceId != dmDeviceInfo.deviceId) { + CLOGE("Invalid device id<%s-%s>", device.deviceId.c_str(), dmDeviceInfo.deviceId); + return false; + } + + DeviceInfoCollection data = { + .device = device, + .dmDeviceInfo = dmDeviceInfo, + .state = RemoteDeviceState::FOUND, + .networkId = dmDeviceInfo.networkId, + }; + + std::lock_guard lock(mutex_); + if (HasDeviceLocked(device.deviceId)) { + CLOGW("Has a device with the same device id(%s)!", device.deviceId.c_str()); + data.state = GetDeviceStateLocked(device.deviceId); + RemoveDeivceLocked(device.deviceId); + } + + data.device.sessionKey = nullptr; + devices_.push_back(data); + return true; +} + +bool CastDeviceDataManager::HasDevice(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + return HasDeviceLocked(deviceId); +} + +std::optional CastDeviceDataManager::GetDeviceByDeviceId(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return std::nullopt; + } + return it->device; +} + +std::optional CastDeviceDataManager::GetDeviceByTransId(int transportId) +{ + if (transportId <= INVALID_ID) { + CLOGE("Invalid session id, %d", transportId); + return std::nullopt; + } + + std::lock_guard lock(mutex_); + for (auto it = devices_.begin(); it != devices_.end(); it++) { + if (it->transportId == transportId) { + return it->device; + } + } + return std::nullopt; +} + +std::optional CastDeviceDataManager::GetDmDevice(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return std::nullopt; + } + return it->dmDeviceInfo; +} + +bool CastDeviceDataManager::UpdateDevice(const CastInnerRemoteDevice &device) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(device.deviceId); + if (it == devices_.end()) { + return false; + } + if (it->device.deviceName != device.deviceName) { + CLOGW("Different devices name: old:%s, new:%s", it->device.deviceName.c_str(), device.deviceName.c_str()); + } + + it->device = device; + it->device.sessionKey = nullptr; + + return true; +} + +void CastDeviceDataManager::RemoveDevice(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + RemoveDeivceLocked(deviceId); +} + +bool CastDeviceDataManager::SetDeviceTransId(const std::string &deviceId, int transportId) +{ + if (transportId <= INVALID_ID) { + CLOGE("Invalid params: id(%d)", transportId); + return false; + } + + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return false; + } + + if (it->transportId != INVALID_ID) { + CLOGE("Device(%s) has matched a session id(%d) in the DB", deviceId.c_str(), it->transportId); + return false; + } + it->transportId = transportId; + return true; +} + +int CastDeviceDataManager::GetDeviceTransId(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return INVALID_ID; + } + return it->transportId; +} + +int CastDeviceDataManager::ResetDeviceTransId(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return INVALID_ID; + } + + int tmp = it->transportId; + it->transportId = INVALID_ID; + return tmp; +} + +bool CastDeviceDataManager::SetDeviceRole(const std::string &deviceId, bool isSink) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return false; + } + + it->isSink = isSink; + return true; +} + +std::optional CastDeviceDataManager::GetDeviceRole(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return std::nullopt; + } + + return it->isSink; +} + +bool CastDeviceDataManager::SetDeviceNetworkId(const std::string &deviceId, const std::string &networkId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return false; + } + + it->networkId = networkId; + return true; +} + +std::optional CastDeviceDataManager::GetDeviceNetworkId(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return std::nullopt; + } + + return it->networkId; +} + +bool CastDeviceDataManager::SetDeviceIsActiveAuth(const std::string &deviceId, bool isActiveAuth) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return false; + } + it->isActiveAuth = isActiveAuth; + return true; +} + +std::optional CastDeviceDataManager::GetDeviceIsActiveAuth(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return std::nullopt; + } + return it->isActiveAuth; +} + +bool CastDeviceDataManager::SetDeviceState(const std::string &deviceId, RemoteDeviceState state) +{ + std::lock_guard lock(mutex_); + auto it = GetDeviceLocked(deviceId); + if (it == devices_.end()) { + return false; + } + it->state = state; + return true; +} + +RemoteDeviceState CastDeviceDataManager::GetDeviceState(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + return GetDeviceStateLocked(deviceId); +} + +bool CastDeviceDataManager::IsDeviceConnecting(const std::string &deviceId) +{ + return GetDeviceState(deviceId) == RemoteDeviceState::CONNECTING; +} + +bool CastDeviceDataManager::IsDeviceConnected(const std::string &deviceId) +{ + return GetDeviceState(deviceId) == RemoteDeviceState::CONNECTED; +} + +bool CastDeviceDataManager::IsDeviceUsed(const std::string &deviceId) +{ + auto state = GetDeviceState(deviceId); + return state == RemoteDeviceState::CONNECTING || state == RemoteDeviceState::CONNECTED; +} + +bool CastDeviceDataManager::HasDeviceLocked(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("Empty device id!"); + return false; + } + + for (const auto &device : devices_) { + if (device.device.deviceId == deviceId) { + return true; + } + } + + return false; +} + +std::vector::iterator CastDeviceDataManager::GetDeviceLocked( + const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("Empty device id!"); + return devices_.end(); + } + + for (auto it = devices_.begin(); it != devices_.end(); it++) { + if (it->device.deviceId == deviceId) { + return it; + } + } + CLOGW("Can't find the device(%s)!", deviceId.c_str()); + return devices_.end(); +} + +void CastDeviceDataManager::RemoveDeivceLocked(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("Empty device id!"); + return; + } + + for (auto it = devices_.begin(); it != devices_.end(); it++) { + if (it->device.deviceId == deviceId) { + devices_.erase(it); + return; + } + } +} + +RemoteDeviceState CastDeviceDataManager::GetDeviceStateLocked(const std::string &deviceId) +{ + auto it = GetDeviceLocked(deviceId); + return (it != devices_.end()) ? it->state : RemoteDeviceState::UNKNOWN; +} + +int CastDeviceDataManager::GetSessionIdByDeviceId(const std::string &deviceId) +{ + if (deviceId.empty()) { + CLOGE("Empty device id!"); + return INVALID_ID; + } + + for (auto it = devices_.begin(); it != devices_.end(); it++) { + if (it->device.deviceId == deviceId) { + return it->device.sessionId; + } + } + return INVALID_ID; +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS diff --git a/service/src/device_manager/src/connection_manager.cpp b/service/src/device_manager/src/connection_manager.cpp new file mode 100644 index 0000000..4c32096 --- /dev/null +++ b/service/src/device_manager/src/connection_manager.cpp @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: implement the cast source connect + * Author: zhangge + * Create: 2022-08-23 + */ + +#include "connection_manager.h" + +#include + +#include "dm_constants.h" +#include "json.hpp" +#include "securec.h" + +#include "cast_engine_dfx.h" +#include "cast_engine_log.h" +#include "discovery_manager.h" +#include "session.h" + +using nlohmann::json; +using OHOS::DistributedHardware::DeviceManager; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Connection-Manager"); +namespace { +constexpr char SESSION_NAME[] = "CastPlusSessionName"; + +constexpr int SOFTBUS_OK = 0; +constexpr int DM_OK = 0; + +constexpr int AUTH_WITH_PIN = 1; + +const std::string VERSION_KEY = "version"; +const std::string OPERATION_TYPE_KEY = "operType"; +const std::string SEQUENCE_NUMBER = "sequenceNumber"; +const std::string DATA_KEY = "data"; + +const std::string DEVICE_ID_KEY = "deviceId"; +const std::string DEVICE_NAME_KEY = "deviceName"; +const std::string KEY_SESSION_ID = "sessionId"; + +const std::string VERSION = "OH1.0"; +constexpr int OPERATION_CONSULT = 3; + +constexpr int FIRST_PRIO_INDEX = 0; +constexpr int SECOND_PRIO_INDEX = 1; +constexpr int THIRD_PRIO_INDEX = 2; +constexpr int MAX_LINK_TYPE_NUM = 3; + +DmDeviceInfo GetDmDeviceInfo(const std::string &deviceId) +{ + std::vector trustedDevices; + if (DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", trustedDevices) != DM_OK) { + return {}; + } + + for (const auto &device : trustedDevices) { + if (device.deviceId == deviceId) { + return device; + } + } + + return {}; +} +} // namespace + +namespace CastSink { +int OnSessionOpened(int sessionId, int result) +{ + CLOGD("OnSessionOpened, session id = %{public}d, result is %{public}d", sessionId, result); + if (sessionId <= INVALID_ID || result != SOFTBUS_OK) { + return result; + } + + ConnectionManager::GetInstance().OnConsultSessionOpened(sessionId, false); + return SOFTBUS_OK; +} + +void OnSessionClosed(int sessionId) +{ + CLOGD("OnSessionClosed, session id = %{public}d", sessionId); + if (sessionId <= INVALID_ID) { + return; + } +} + +void OnBytesReceived(int sessionId, const void *data, unsigned int dataLen) +{ + CLOGD("OnBytesReceived,session id = %{public}d, len = %{public}u", sessionId, dataLen); + if (sessionId <= INVALID_ID || data == nullptr || dataLen == 0) { + return; + } + + ConnectionManager::GetInstance().OnConsultDataReceived(sessionId, data, dataLen); +} + +ISessionListener g_sinkSessionListener = { + OnSessionOpened, OnSessionClosed, OnBytesReceived, nullptr, nullptr, nullptr +}; +} + +namespace CastSource { +int OnSessionOpened(int sessionId, int result) +{ + CLOGI("OnSessionOpened, session id = %{public}d, result is %{public}d", sessionId, result); + if (sessionId <= INVALID_ID || result != SOFTBUS_OK) { + return result; + } + + ConnectionManager::GetInstance().OnConsultSessionOpened(sessionId, true); + return SOFTBUS_OK; +} + +void OnSessionClosed(int sessionId) +{ + CLOGI("OnSessionClosed, session id = %{public}d", sessionId); + if (sessionId <= INVALID_ID) { + return; + } + std::thread([]() { RemoveSessionServer(PKG_NAME, SESSION_NAME); }).detach(); +} + +ISessionListener g_sourceSessionListener = { OnSessionOpened, OnSessionClosed, nullptr, nullptr, nullptr, nullptr }; +} // CastSource + +ConnectionManager &ConnectionManager::GetInstance() +{ + static ConnectionManager instance{}; + return instance; +} + +void ConnectionManager::Init(std::shared_ptr listener) +{ + CLOGD("ConnectionManager init start"); + if (listener == nullptr) { + CLOGE("The input listener is null!"); + return; + } + + if (HasListener()) { + CLOGE("Already inited"); + return; + } + + if (DeviceManager::GetInstance().RegisterDevStateCallback(PKG_NAME, "", + std::make_shared()) != DM_OK) { + CLOGE("Failed to register device state callback"); + return; + } + + SetListener(listener); + CLOGD("ConnectionManager init done"); +} + +void ConnectionManager::Deinit() +{ + CLOGD("Deinit start"); + ResetListener(); + DisableDiscoverable(); + DeviceManager::GetInstance().UnRegisterDevStateCallback(PKG_NAME); +} + +bool ConnectionManager::IsDeviceTrusted(const std::string &deviceId, std::string &networkId) +{ + std::vector trustedDevices; + if (DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", trustedDevices) != DM_OK) { + return false; + } + + for (const auto &device : trustedDevices) { + CLOGV("Trusted device id(%s)", device.deviceId); + if (device.deviceId == deviceId) { + networkId = device.networkId; + return true; + } + } + + return false; +} + +bool ConnectionManager::ConnectDevice(const CastInnerRemoteDevice &dev) +{ + auto &deviceId = dev.deviceId; + CLOGI("ConnectDevice in, %s", deviceId.c_str()); + + if (CastDeviceDataManager::GetInstance().IsDeviceUsed(deviceId)) { + return true; + } + + if (!UpdateDeviceState(deviceId, RemoteDeviceState::CONNECTING)) { + CLOGE("device(%s) is missing", deviceId.c_str()); + return false; + } + + DiscoveryManager::GetInstance().StopDiscovery(); + std::string networkId; + if (IsDeviceTrusted(dev.deviceId, networkId)) { + if (!CastDeviceDataManager::GetInstance().SetDeviceNetworkId(deviceId, networkId) || + !OpenConsultSession(deviceId)) { + RemoveSessionServer(PKG_NAME, SESSION_NAME); + (void)UpdateDeviceState(deviceId, RemoteDeviceState::FOUND); + return false; + } + + (void)UpdateDeviceState(deviceId, RemoteDeviceState::CONNECTED); + return true; + } + + if (!AuthenticateDevice(dev.deviceId)) { + (void)UpdateDeviceState(deviceId, RemoteDeviceState::FOUND); + return false; + } + + return true; +} + +bool ConnectionManager::AuthenticateDevice(const std::string &deviceId) +{ + auto dmDeviceInfo = CastDeviceDataManager::GetInstance().GetDmDevice(deviceId); + if (dmDeviceInfo == std::nullopt) { + CLOGE("The device(%s) is missing", deviceId.c_str()); + return false; + } + + std::string extraInfo = R"({ + "targetPkgName": "CastEngineService", + "appName": "CastEngineService", + "appDescription": "Cast engine service", + "business": '0' + })"; + int ret = DeviceManager::GetInstance().AuthenticateDevice(PKG_NAME, AUTH_WITH_PIN, *dmDeviceInfo, extraInfo, + std::make_shared()); + if (ret != DM_OK) { + CLOGE("ConnectDevice AuthenticateDevice fail, ret = %{public}d)", ret); + CastEngineDfx::WriteErrorEvent(AUTHENTICATE_DEVICE_FAIL); + return false; + } + + CastDeviceDataManager::GetInstance().SetDeviceIsActiveAuth(deviceId, true); + CLOGI("Finish to authenticate device!"); + return true; +} + +bool ConnectionManager::OpenConsultSession(const std::string &deviceId) +{ + // Only the source end enters this path, so the softbus server should be created firstly. + int32_t ret = CreateSessionServer(PKG_NAME, SESSION_NAME, &CastSource::g_sourceSessionListener); + if (ret != SOFTBUS_OK) { + CLOGE("CreateSessionServer failed, ret:%d", ret); + CastEngineDfx::WriteErrorEvent(SOURCE_CREATE_SESSION_SERVER_FAIL); + return false; + } + + // The session can only be opened using a network ID instead of a UDID in OH system + auto networkId = CastDeviceDataManager::GetInstance().GetDeviceNetworkId(deviceId); + if (networkId == std::nullopt) { + return false; + } + + SessionAttribute attr {}; + attr.dataType = TYPE_BYTES; + attr.linkTypeNum = MAX_LINK_TYPE_NUM; + attr.linkType[FIRST_PRIO_INDEX] = LINK_TYPE_WIFI_P2P; + attr.linkType[SECOND_PRIO_INDEX] = LINK_TYPE_WIFI_WLAN_5G; + attr.linkType[THIRD_PRIO_INDEX] = LINK_TYPE_WIFI_WLAN_2G; + auto transportId = OpenSession(SESSION_NAME, SESSION_NAME, networkId->c_str(), "", &attr); + if (transportId <= INVALID_ID) { + CLOGW("Failed to open session, and try again, id:%{public}d", transportId); + transportId = OpenSession(SESSION_NAME, SESSION_NAME, networkId->c_str(), "", &attr); + if (transportId <= INVALID_ID) { + CLOGE("Failed to open session finally, id:%{public}d", transportId); + CastEngineDfx::WriteErrorEvent(OPEN_SESSION_FAIL); + RemoveSessionServer(PKG_NAME, SESSION_NAME); + return false; + } + } + if (!CastDeviceDataManager::GetInstance().SetDeviceTransId(deviceId, transportId)) { + CloseSession(transportId); + RemoveSessionServer(PKG_NAME, SESSION_NAME); + return false; + } + + UpdateDeviceState(deviceId, RemoteDeviceState::CONNECTED); + CLOGD("Out, sessionId = %{public}d", transportId); + return true; +} + +std::unique_ptr ConnectionManager::GetLocalDeviceInfo() +{ + CLOGD("GetLocalDeviceInfo in"); + DmDeviceInfo local; + if (DeviceManager::GetInstance().GetLocalDeviceInfo(PKG_NAME, local) != DM_OK) { + CLOGE("Cannot get the local device info from DM"); + return nullptr; + }; + auto device = std::make_unique(); + device->deviceId = local.deviceId; + device->deviceType = DeviceType::DEVICE_CAST_PLUS; + device->deviceName = local.deviceName; + CLOGD("GetLocalDeviceInfo out"); + return device; +} + +void ConnectionManager::SendConsultData(const CastInnerRemoteDevice &device) +{ + CLOGD("In"); + + int transportId = CastDeviceDataManager::GetInstance().GetDeviceTransId(device.deviceId); + if (transportId == INVALID_ID) { + return; + } + + auto local = GetLocalDeviceInfo(); + if (local == nullptr) { + return; + } + json body; + body[DEVICE_ID_KEY] = local->deviceId; + body[DEVICE_NAME_KEY] = local->deviceName; + body[KEY_SESSION_ID] = device.sessionId; + + json data; + data[VERSION_KEY] = VERSION; + data[OPERATION_TYPE_KEY] = OPERATION_CONSULT; + data[SEQUENCE_NUMBER] = rand(); + data[DATA_KEY] = body; + + std::string dataStr = data.dump(); + int ret = SendBytes(transportId, dataStr.c_str(), dataStr.size()); + if (ret != SOFTBUS_OK) { + CLOGE("failed to send consultion data, return:%{public}d", ret); + CastEngineDfx::WriteErrorEvent(SEND_CONSULTION_DATA_FAIL); + return; + } + CLOGD("return:%{public}d, data:%s", ret, dataStr.c_str()); +} + +void ConnectionManager::OnConsultSessionOpened(int transportId, bool isSource) +{ + std::thread([transportId, isSource]() { + if (isSource) { + auto device = CastDeviceDataManager::GetInstance().GetDeviceByTransId(transportId); + if (device == std::nullopt) { + return; + } + ConnectionManager::GetInstance().SendConsultData(*device); + return; + } + ConnectionManager::GetInstance().NotifySessionIsReady(transportId); + }).detach(); + return; +} + +void ConnectionManager::NotifySessionIsReady(int transportId) +{ + int castSessionId = listener_->NotifySessionIsReady(); + if (castSessionId == INVALID_ID) { + return; + } + + std::lock_guard lock(mutex_); + transIdToCastSessionIdMap_.insert({ transportId, castSessionId }); +} + +int ConnectionManager::GetCastSessionId(int transportId) +{ + std::lock_guard lock(mutex_); + for (const auto &element : transIdToCastSessionIdMap_) { + if (element.first == transportId) { + return element.second; + } + } + CLOGE("Invalid transport id:%{public}d", transportId); + return INVALID_ID; +} + +std::unique_ptr ConnectionManager::GetRemoteFromJsonData(const std::string &data) +{ + json jsonObject; + if (!jsonObject.accept(data)) { + CLOGE("something wrong for the json data!"); + return nullptr; + } + jsonObject = json::parse(data, nullptr, false); + if (!jsonObject.contains(DATA_KEY)) { + CLOGE("json object have no data!"); + return nullptr; + } + + json remote = jsonObject[DATA_KEY]; + if (remote.is_discarded()) { + CLOGE("json object discarded!"); + return nullptr; + } + + if (remote.contains(DEVICE_ID_KEY) && !remote[DEVICE_ID_KEY].is_string()) { + CLOGE("DEVICE_ID_KEY json data is not string"); + return nullptr; + } + + if (remote.contains(DEVICE_NAME_KEY) && !remote[DEVICE_NAME_KEY].is_string()) { + CLOGE("DEVICE_NAME_KEY json data is not string"); + return nullptr; + } + + if (remote.contains(KEY_SESSION_ID) && !remote[KEY_SESSION_ID].is_number()) { + CLOGE("KEY_SESSION_ID json data is not number"); + return nullptr; + } + + auto device = std::make_unique(); + device->deviceId = remote.contains(DEVICE_ID_KEY) ? remote[DEVICE_ID_KEY] : ""; + device->deviceName = remote.contains(DEVICE_NAME_KEY) ? remote[DEVICE_NAME_KEY] : ""; + device->deviceType = DeviceType::DEVICE_CAST_PLUS; + if (remote.contains(KEY_SESSION_ID)) { + device->sessionId = remote[KEY_SESSION_ID]; + } + + return device; +} + +void ConnectionManager::OnConsultDataReceived(int transportId, const void *data, unsigned int dataLen) +{ + std::string dataStr(static_cast(data), dataLen); + CLOGD("Received data: len:%{public}u, data:%s", dataLen, dataStr.c_str()); + + auto device = GetRemoteFromJsonData(dataStr); + if (device == nullptr) { + return; + } + const std::string &deviceId = device->deviceId; + auto dmDevice = GetDmDeviceInfo(deviceId); + if (deviceId.compare(dmDevice.deviceId) != 0) { + CLOGE("Failed to get DmDeviceInfo"); + return; + } + int castSessionId = GetCastSessionId(transportId); + if (castSessionId == INVALID_ID) { + return; + } + + if (!CastDeviceDataManager::GetInstance().AddDevice(*device, dmDevice)) { + return; + } + if (!CastDeviceDataManager::GetInstance().SetDeviceRole(deviceId, true) || + !UpdateDeviceState(deviceId, RemoteDeviceState::CONNECTED)) { + CastDeviceDataManager::GetInstance().RemoveDevice(deviceId); + return; + } + if (!listener_->NotifyRemoteDeviceIsReady(castSessionId, *device)) { + CastDeviceDataManager::GetInstance().RemoveDevice(deviceId); + } + + DestroyConsulationSession(deviceId); +} + +void ConnectionManager::DestroyConsulationSession(const std::string &deviceId) +{ + int transportId = CastDeviceDataManager::GetInstance().ResetDeviceTransId(deviceId); + if (transportId != INVALID_ID) { + CloseSession(transportId); + } + + auto isSink = CastDeviceDataManager::GetInstance().GetDeviceRole(deviceId); + if (isSink == std::nullopt || (*isSink)) { + // The sink's Server is only removed when DisableDiscoverable or Deinit is performed. + return; + } + + RemoveSessionServer(PKG_NAME, SESSION_NAME); +} + +void ConnectionManager::DisconnectDevice(const std::string &deviceId) +{ + DiscoveryManager::GetInstance().StopDiscovery(); + if (!CastDeviceDataManager::GetInstance().IsDeviceUsed(deviceId)) { + CLOGE("Device(%s) is not used, remove it", deviceId.c_str()); + CastDeviceDataManager::GetInstance().RemoveDevice(deviceId); + return; + } + + DestroyConsulationSession(deviceId); + auto isActiveAuth = CastDeviceDataManager::GetInstance().GetDeviceIsActiveAuth(deviceId); + if (isActiveAuth == std::nullopt) { + return; + } + auto dmDeviceInfo = CastDeviceDataManager::GetInstance().GetDmDevice(deviceId); + if (dmDeviceInfo == std::nullopt) { + return; + } + + if (*isActiveAuth) { + DeviceManager::GetInstance().UnAuthenticateDevice(PKG_NAME, *dmDeviceInfo); + } + CastDeviceDataManager::GetInstance().RemoveDevice(deviceId); +} + +bool ConnectionManager::EnableDiscoverable() +{ + std::lock_guard lock(mutex_); + if (isDiscoverable_) { + CLOGW("service has been set discoverable"); + return true; + } + + int ret = CreateSessionServer(PKG_NAME, SESSION_NAME, &CastSink::g_sinkSessionListener); + if (ret != 0) { + CLOGE("CreateSessionServer failed, ret = %{public}d", ret); + CastEngineDfx::WriteErrorEvent(SINK_CREATE_SESSION_SERVER_FAIL); + return false; + } + + isDiscoverable_ = true; + return true; +} + +bool ConnectionManager::DisableDiscoverable() +{ + std::lock_guard lock(mutex_); + if (!isDiscoverable_) { + return true; + } + + RemoveSessionServer(PKG_NAME, SESSION_NAME); + isDiscoverable_ = false; + return true; +} + +void ConnectionManager::SetListener(std::shared_ptr listener) +{ + std::lock_guard lock(mutex_); + listener_ = listener; +} + +bool ConnectionManager::HasListener() +{ + std::lock_guard lock(mutex_); + return listener_ != nullptr; +} + +void ConnectionManager::ResetListener() +{ + SetListener(nullptr); +} + +bool ConnectionManager::UpdateDeviceState(const std::string &deviceId, RemoteDeviceState state) +{ + return CastDeviceDataManager::GetInstance().SetDeviceState(deviceId, state); +} + +void ConnectionManager::ReportErrorByListener(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + if (!listener_) { + return; + } + listener_->OnError(deviceId); +} + +void ConnectionManager::NotifyDeviceIsOffline(const std::string &deviceId) +{ + std::lock_guard lock(mutex_); + if (!listener_) { + return; + } + listener_->NotifyDeviceIsOffline(deviceId); +} + +void CastAuthenticateCallback::OnAuthResult(const std::string &deviceId, const std::string &token, int32_t status, + int32_t reason) +{ + if (reason != DM_OK) { + ConnectionManager::GetInstance().ReportErrorByListener(deviceId); + CastEngineDfx::WriteErrorEvent(AUTHENTICATE_DEVICE_FAIL); + } + CLOGI("OnAuthResult, device id:%s, token:%s, status: %{public}d, %{public}d", deviceId.c_str(), token.c_str(), + status, reason); +} + +void CastDeviceStateCallback::OnDeviceOnline(const DmDeviceInfo &deviceInfo) +{ + CLOGI("device(%s) is online", deviceInfo.deviceId); + std::vector devices; + devices.push_back(deviceInfo); + DiscoveryManager::GetInstance().NotifyDeviceIsFound(devices, true, true); +} + +void CastDeviceStateCallback::OnDeviceOffline(const DmDeviceInfo &deviceInfo) +{ + CLOGI("device(%s) is offline", deviceInfo.deviceId); + ConnectionManager::GetInstance().NotifyDeviceIsOffline(deviceInfo.deviceId); +} + +void CastDeviceStateCallback::OnDeviceChanged(const DmDeviceInfo &deviceInfo) +{ + CLOGI("device(%s) is changed", deviceInfo.deviceId); +} + +void CastDeviceStateCallback::OnDeviceReady(const DmDeviceInfo &deviceInfo) +{ + std::string deviceId = deviceInfo.deviceId; + CLOGI("device(%s) is ready, network:%s", deviceId.c_str(), deviceInfo.networkId); + if (!CastDeviceDataManager::GetInstance().SetDeviceNetworkId(deviceId, deviceInfo.networkId)) { + return; + } + auto isActiveAuth = CastDeviceDataManager::GetInstance().GetDeviceIsActiveAuth(deviceId); + if (isActiveAuth == std::nullopt || !(*isActiveAuth)) { + return; + } + ConnectionManager::GetInstance().OpenConsultSession(deviceId); +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS diff --git a/service/src/device_manager/src/discovery_manager.cpp b/service/src/device_manager/src/discovery_manager.cpp new file mode 100644 index 0000000..39b6265 --- /dev/null +++ b/service/src/device_manager/src/discovery_manager.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: implement the cast source discovery + * Author: zhangge + * Create: 2022-08-23 + */ + +#include "discovery_manager.h" +#include "connection_manager.h" +#include "cast_device_data_manager.h" +#include "cast_engine_dfx.h" +#include "cast_engine_log.h" +#include "dm_constants.h" +#include "securec.h" + +using namespace OHOS::DistributedHardware; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Discovery-Manager"); + +namespace { +constexpr int WIFI_SUBSCRIBE_ID = 0; + +DeviceType ConvertDeviceType(uint16_t deviceTypeId) +{ + switch (deviceTypeId) { + case DEVICE_TYPE_TV: + return DeviceType::DEVICE_HW_TV; + case DEVICE_TYPE_PAD: + return DeviceType::DEVICE_PAD; + case DEVICE_TYPE_CAR: + return DeviceType::DEVICE_HICAR; + case DEVICE_TYPE_2IN1: + return DeviceType::DEVICE_TYPE_2IN1; + default: + return DeviceType::DEVICE_CAST_PLUS; + } +} +} // namespace + +void CastDmInitCallback::OnRemoteDied() +{ + CLOGE("DM is dead, deinit the DiscoveryManager"); + DiscoveryManager::GetInstance().Deinit(); +} + +DiscoveryManager &DiscoveryManager::GetInstance() +{ + static DiscoveryManager instance{}; + return instance; +} + +void DiscoveryManager::Init(std::shared_ptr listener) +{ + CLOGD("init start"); + if (listener == nullptr) { + CLOGE("The input listener is null!"); + return; + } + + if (HasListener()) { + CLOGE("Already inited"); + return; + } + + if (DeviceManager::GetInstance().InitDeviceManager(PKG_NAME, std::make_shared()) != DM_OK) { + CLOGE("Failed to InitDeviceManager"); + return; + } + + SetListener(listener); + CLOGD("init done"); +} + +void DiscoveryManager::Deinit() +{ + if (!HasListener()) { + return; + } + + StopDiscovery(); + ResetListener(); + DeviceManager::GetInstance().UnInitDeviceManager(PKG_NAME); +} + +void DiscoveryManager::GetAndReportTrustedDevices() +{ + std::vector dmDevices; + auto result = DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", dmDevices); + if (result != DM_OK || dmDevices.size() == 0) { + CLOGW("No trusted devices, result:%d", result); + return; + } + + NotifyDeviceIsFound(dmDevices, true, false); +} + +void DiscoveryManager::StartDmDiscovery() +{ + OHOS::DistributedHardware::DmSubscribeInfo subInfo = { + .subscribeId = WIFI_SUBSCRIBE_ID, + .mode = DM_DISCOVER_MODE_ACTIVE, + .medium = DM_AUTO, + .freq = DM_SUPER_HIGH, + .isSameAccount = false, + .isWakeRemote = false, + .capability = "ddmpCapability", + }; + int32_t ret = DeviceManager::GetInstance().StartDeviceDiscovery(PKG_NAME, subInfo, "", + std::make_shared()); + if (ret != DM_OK && ret != ERR_DM_DISCOVERY_REPEATED) { + CLOGE("Failed to start discovery, ret:%d", ret); + CastEngineDfx::WriteErrorEvent(START_DISCOVERY_FAIL); + } +} + +void DiscoveryManager::StartDiscovery() +{ + CLOGI("StartDiscovery in"); + StartDmDiscovery(); + GetAndReportTrustedDevices(); +} + +void DiscoveryManager::StopDiscovery() +{ + CLOGD("StopDiscovery in"); + DeviceManager::GetInstance().StopDeviceDiscovery(PKG_NAME, WIFI_SUBSCRIBE_ID); +} + +void DiscoveryManager::SetListener(std::shared_ptr listener) +{ + std::lock_guard lock(mutex_); + listener_ = listener; +} + +bool DiscoveryManager::HasListener() +{ + std::lock_guard lock(mutex_); + return listener_ != nullptr; +} + +void DiscoveryManager::ResetListener() +{ + SetListener(nullptr); +} + +void DiscoveryManager::OnDeviceInfoFound(uint16_t subscribeId, const DmDeviceInfo &dmDeviceInfo) +{ + std::string networkId = dmDeviceInfo.networkId; + CLOGD("OnDeviceInfoFound deviceName is %{public}s", dmDeviceInfo.deviceName); + bool ret = ConnectionManager::GetInstance().IsDeviceTrusted(dmDeviceInfo.deviceId, networkId); + if (!ret) { + NotifyDeviceIsFound({ dmDeviceInfo }, false, false); + return; + } + NotifyDeviceIsFound({ dmDeviceInfo }, true, false); +} + +void DiscoveryManager::NotifyDeviceIsFound(const std::vector &dmDevices, bool isTrusted, bool isOnline) +{ + std::vector devices; + for (const auto &dmDevice : dmDevices) { + CastInnerRemoteDevice newDevice = { + .deviceId = dmDevice.deviceId, + .deviceName = dmDevice.deviceName, + .deviceType = ConvertDeviceType(dmDevice.deviceTypeId), + .subDeviceType = SubDeviceType::SUB_DEVICE_DEFAULT, + .channelType = ChannelType::SOFT_BUS + }; + if (!isTrusted) { + newDevice.subDeviceType = SubDeviceType::SUB_DEVICE_MATEBOOK_PAD; + } + if (!isOnline && !CastDeviceDataManager::GetInstance().AddDevice(newDevice, dmDevice)) { + return; + } + devices.push_back(newDevice); + } + std::lock_guard lock(mutex_); + listener_->OnDeviceFound(devices); +} + +void CastDiscoveryCallback::OnDiscoverySuccess(uint16_t subscribeId) +{ + CLOGI("OnDiscoverySuccess, subscribe id:%{public}u", subscribeId); +} + +void CastDiscoveryCallback::OnDiscoveryFailed(uint16_t subscribeId, int32_t failedReason) +{ + CLOGI("OnDiscoveryFailed, subscribe id:%{public}u, reason:%{public}d", subscribeId, failedReason); +} + +void CastDiscoveryCallback::OnDeviceFound(uint16_t subscribeId, const DmDeviceInfo &deviceInfo) +{ + CLOGI("OnDeviceInfoFound in, subscribe id:%{public}u, device id:%s, device name:%s", subscribeId, + deviceInfo.deviceId, deviceInfo.deviceName); + DiscoveryManager::GetInstance().OnDeviceInfoFound(subscribeId, deviceInfo); +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS diff --git a/test/BUILD.gn b/test/BUILD.gn new file mode 100644 index 0000000..41dbdbf --- /dev/null +++ b/test/BUILD.gn @@ -0,0 +1,112 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + +import("//build/ohos.gni") +import("//build/ohos_var.gni") +import("//build/test.gni") +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_session_config") { + include_dirs = [ + "${cast_engine_interfaces}/inner_api", + "${cast_engine_interfaces}/inner_api/include", + "//base/security/access_token/interfaces/innerkits/nativetoken/include", + "//base/security/access_token/interfaces/innerkits/accesstoken/include", + "//base/security/access_token/interfaces/innerkits/token_setproc/include", + ] +} +ohos_unittest("cast_session_manager_test") { + module_out_path = "/cast_engine/cast_engine/common" + + testonly = true + + sources = [ + "unittest/phone/cast_session_manager_test.cpp", + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + deps = [ + "${cast_engine_common}:cast_engine_common_sources", + "${cast_engine_interfaces}/inner_api:cast_engine_client" + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "googletest:gtest", + "hilog:libhilog", + "ipc:ipc_core" + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("cast_session_test") { + module_out_path = "cast_engine/cast_engine/common" + + testonly = true + + sources = [ + "unittest/phone/cast_session_test.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_engine_service}/src/device_manager/include" + ] + + deps = [ + "${cast_engine_service}/src/device_manager:cast_discovery", + "${cast_engine_common}:cast_engine_common_sources", + "${cast_engine_interfaces}/inner_api:cast_engine_client" + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "device_manager:devicemanagersdk", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +group("cast_unittest") { + testonly = true + deps = [ + ":cast_session_manager_test", + ":cast_session_test", + "unittest/phone/stream:stream_unittest", + ] +} \ No newline at end of file diff --git a/test/fuzztest/BUILD.gn b/test/fuzztest/BUILD.gn new file mode 100644 index 0000000..5828dae --- /dev/null +++ b/test/fuzztest/BUILD.gn @@ -0,0 +1,22 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +group("fuzztest") { + testonly = true + + deps = [ + "castsessionimplstub_fuzzer:fuzztest", + "castsessionmanagerservicestub_fuzzer:fuzztest", + "streamplayerimplstub_fuzzer:fuzztest", + ] +} diff --git a/test/fuzztest/castsessionimplstub_fuzzer/BUILD.gn b/test/fuzztest/castsessionimplstub_fuzzer/BUILD.gn new file mode 100644 index 0000000..cf855ab --- /dev/null +++ b/test/fuzztest/castsessionimplstub_fuzzer/BUILD.gn @@ -0,0 +1,68 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +##############################fuzztest########################################## +ohos_fuzztest("CastSessionImplStubFuzzTest") { + module_out_path = "cast_engine/cast_engine" + fuzz_config_file = "$cast_engine_root/test/fuzztest/castsessionimplstub_fuzzer" + + include_dirs = [ + "$cast_engine_common/include/private", + "$cast_engine_interfaces/inner_api/include", + "$cast_engine_root/test/fuzztest/common_fuzzer", + "${cast_session_stream_path}/include", + "${cast_session_stream_path}/src/channel/include", + "${cast_session_stream_path}/src/rtsp/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/utils/include", + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ + "cast_session_impl_stub_fuzzer.cpp", + "$cast_engine_root/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp", + ] + deps = [ + "${cast_session_stream_path}:cast_session", + "//third_party/openssl:libcrypto_shared", + ] + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "c_utils:utils", + "graphic_2d:surface", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_core", + ] +} +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + ":CastSessionImplStubFuzzTest", + ] +} +############################################################################### diff --git a/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.cpp b/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.cpp new file mode 100644 index 0000000..c8047a0 --- /dev/null +++ b/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: CastSessionImplStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-29 + */ + +#include "cast_session_impl_stub_fuzzer.h" + +#include + +#include "add_cast_engine_token_fuzzer.h" +#include "cast_engine_common.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_session_impl.h" + +using namespace OHOS::CastEngine::CastEngineService; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-SessionImplStubFuzzer"); + +namespace { +enum { + REGISTER_LISTENER = 1, + UNREGISTER_LISTENER, + ADD_DEVICE, + REMOVE_DEVICE, + START_AUTH, + GET_SESSION_ID, + GET_DEVICE_STATE, + SET_SESSION_PROPERTY, + CREAT_MIRROR_PLAYER, + CREAT_STREAM_PLAYER, + RELEASE, + NOTIFY_EVENT, + SET_CAST_MODE, +}; +} // namespace + +int32_t CastSessionImplStubOnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + OHOS::CastEngine::CastSessionProperty property{}; + OHOS::CastEngine::CastLocalDevice localDevice{}; + sptr castSessionImpl = new (std::nothrow) CastSessionImpl(property, localDevice); + if (!castSessionImpl) { + CLOGE("CastSessionImpl is null"); + return CAST_ENGINE_ERROR; + } + castSessionImpl->Init(); + MessageOption option; + CLOGE("CastSessionImplStubOnRemoteRequest, code:%{public}d", code); + return castSessionImpl->OnRemoteRequest(code, data, reply, option); +} + +int32_t UnregisterListenerFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (CastSessionImplStubOnRemoteRequest(UNREGISTER_LISTENER, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + return reply.ReadInt32(); +} + +int32_t RemoveDeviceFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + std::string deviceId(reinterpret_cast(data), size); + + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteString(deviceId)) { + return CAST_ENGINE_ERROR; + } + + int32_t ret = CastSessionImplStubOnRemoteRequest(REMOVE_DEVICE, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetSessionIdFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + + int32_t ret = CastSessionImplStubOnRemoteRequest(GET_SESSION_ID, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetDeviceStateFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + std::string deviceId(reinterpret_cast(data), size); + + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteString(deviceId)) { + return CAST_ENGINE_ERROR; + } + + int32_t ret = CastSessionImplStubOnRemoteRequest(GET_DEVICE_STATE, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CreateMirrorPlayerFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionImplStubOnRemoteRequest(CREAT_MIRROR_PLAYER, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t CreateStreamPlayerFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionImplStubOnRemoteRequest(CREAT_STREAM_PLAYER, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t ReleaseFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionImplStubOnRemoteRequest(RELEASE, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetCastModeFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t mode = *reinterpret_cast(data); + std::string jsonParam(reinterpret_cast(data), size); + MessageParcel dataParcel; + MessageParcel reply; + + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(mode)) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteString(jsonParam)) { + return CAST_ENGINE_ERROR; + } + if (CastSessionImplStubOnRemoteRequest(SET_CAST_MODE, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t NotifyEventFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t eventId = *reinterpret_cast(data); + std::string jsonParam(reinterpret_cast(data), size); + MessageParcel dataParcel; + MessageParcel reply; + + if (!dataParcel.WriteInterfaceToken(CastSessionImpl::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(eventId)) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteString(jsonParam)) { + return CAST_ENGINE_ERROR; + } + if (CastSessionImplStubOnRemoteRequest(NOTIFY_EVENT, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + return CAST_ENGINE_SUCCESS; +} + +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + OHOS::AddCastEngineTokenFuzzer::AddCastEngineToken(); + UnregisterListenerFuzzTest(data, size); + RemoveDeviceFuzzTest(data, size); + GetSessionIdFuzzTest(data, size); + GetDeviceStateFuzzTest(data, size); + SetCastModeFuzzTest(data, size); + NotifyEventFuzzTest(data, size); + CreateMirrorPlayerFuzzTest(data, size); + CreateStreamPlayerFuzzTest(data, size); + ReleaseFuzzTest(data, size); + return 0; +} + diff --git a/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.h b/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.h new file mode 100644 index 0000000..715e918 --- /dev/null +++ b/test/fuzztest/castsessionimplstub_fuzzer/cast_session_impl_stub_fuzzer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: CastSessionImplStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-29 + */ + +#ifndef CAST_SESSION_IMPL_STUB_FUZZER_H +#define CAST_SESSION_IMPL_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "castsessionimplstub_fuzzer" + +#endif // CAST_SESSION_IMPL_STUB_FUZZER_H \ No newline at end of file diff --git a/test/fuzztest/castsessionimplstub_fuzzer/project.xml b/test/fuzztest/castsessionimplstub_fuzzer/project.xml new file mode 100644 index 0000000..4fdbc40 --- /dev/null +++ b/test/fuzztest/castsessionimplstub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/test/fuzztest/castsessionmanagerservicestub_fuzzer/BUILD.gn b/test/fuzztest/castsessionmanagerservicestub_fuzzer/BUILD.gn new file mode 100644 index 0000000..a82bc00 --- /dev/null +++ b/test/fuzztest/castsessionmanagerservicestub_fuzzer/BUILD.gn @@ -0,0 +1,75 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +##############################fuzztest########################################## +ohos_fuzztest("CastSessionManagerServiceStubFuzzTest") { + module_out_path = "cast_engine/cast_engine" + fuzz_config_file = "$cast_engine_root/test/fuzztest/castsessionmanagerservicestub_fuzzer" + + include_dirs = [ + "$cast_engine_common/include/private", + "$cast_engine_interfaces/inner_api/include", + "$cast_engine_root/test/fuzztest/common_fuzzer", + "$cast_engine_service/include", + "$cast_engine_service/src/device_manager/include", + "//third_party/json/single_include/nlohmann", + "//third_party/jsoncpp/include" + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ + "cast_session_manager_service_stub_fuzzer.cpp", + "$cast_engine_service/src/cast_session_manager_service.cpp", + "$cast_engine_service/src/cast_session_manager_service_stub.cpp", + "$cast_engine_service/src/cast_service_listener_impl_proxy.cpp", + "$cast_engine_root/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp", + ] + deps = [ + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + "$cast_engine_service/src/device_manager:cast_discovery", + "${cast_session_stream_path}:cast_session", + "//third_party/openssl:libcrypto_shared", + ] + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "c_utils:utils", + "device_manager:devicemanagersdk", + "graphic_2d:surface", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_core", + "safwk:system_ability_fwk", + ] +} +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + ":CastSessionManagerServiceStubFuzzTest", + ] +} +############################################################################### diff --git a/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.cpp b/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.cpp new file mode 100644 index 0000000..2808bc9 --- /dev/null +++ b/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: CastSessionManagerServiceStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-29 + */ + +#include "cast_session_manager_service_stub_fuzzer.h" + +#include "add_cast_engine_token_fuzzer.h" +#include "cast_engine_common.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_session_manager_service.h" + +using namespace OHOS::CastEngine::CastEngineService; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-SessionManagerServiceStubFuzzer"); +namespace { +enum { + REGISTER_LISTENER = 0, + UNREGISTER_LISTENER, + RELEASE, + SET_LOCAL_DEVICE, + CREATE_CAST_SESSION, + SET_SINK_SESSION_CAPACITY, + START_DISCOVERY, + SET_DISCOVERABLE, + STOP_DISCOVERY, + GET_CAST_SESSION +}; +} // namespace + +int32_t CastSessionManagerServiceStubOnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + bool runOnCreate = false; + sptr service = + new (std::nothrow) CastSessionManagerService(CAST_ENGINE_SA_ID, runOnCreate); + if (!service) { + CLOGE("CastSessionManagerService is null"); + return CAST_ENGINE_ERROR; + } + MessageOption option; + CLOGE("CastSessionManagerServiceStubOnRemoteRequest, code:%{public}d", code); + return service->OnRemoteRequest(code, data, reply, option); +} + +int32_t UnregisterListenerFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(UNREGISTER_LISTENER, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t ReleaseFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(RELEASE, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetSinkSessionCapacityFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t sessionCapacity = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(sessionCapacity)) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(SET_SINK_SESSION_CAPACITY, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StartDiscoveryFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t protocols = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(protocols)) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(START_DISCOVERY, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret == ERR_INVALID_DATA) { + return ERR_INVALID_PARAM; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetDiscoverableFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(bool))) { + return CAST_ENGINE_ERROR; + } + bool enable = static_cast(*data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteBool(enable)) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(SET_DISCOVERABLE, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StopDiscoveryFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + int32_t ret = CastSessionManagerServiceStubOnRemoteRequest(STOP_DISCOVERY, dataParcel, reply); + if (ret == ERR_UNKNOWN_TRANSACTION) { + return ERR_NO_PERMISSION; + } else if (ret != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetCastSessionFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + std::string sessionId(reinterpret_cast(data), size); + if (!dataParcel.WriteInterfaceToken(CastSessionManagerService::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteString(sessionId)) { + return CAST_ENGINE_ERROR; + } + if (CastSessionManagerServiceStubOnRemoteRequest(GET_CAST_SESSION, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + auto object = reply.ReadRemoteObject(); + if (object == nullptr) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} +} // namespace CastEngineService +} // namespace CastEngine +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + OHOS::AddCastEngineTokenFuzzer::AddCastEngineToken(); + UnregisterListenerFuzzTest(data, size); + ReleaseFuzzTest(data, size); + SetSinkSessionCapacityFuzzTest(data, size); + StartDiscoveryFuzzTest(data, size); + SetDiscoverableFuzzTest(data, size); + StopDiscoveryFuzzTest(data, size); + GetCastSessionFuzzTest(data, size); + return 0; +} diff --git a/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.h b/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.h new file mode 100644 index 0000000..b599d2a --- /dev/null +++ b/test/fuzztest/castsessionmanagerservicestub_fuzzer/cast_session_manager_service_stub_fuzzer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: CastSessionManagerServiceStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-29 + */ + +#ifndef CAST_SESSION_MANAGER_SERVICE_STUB_FUZZER_H +#define CAST_SESSION_MANAGER_SERVICE_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "castsessionmanagerservicestub_fuzzer" + +#endif // CAST_SESSION_MANAGER_SERVICE_STUB_FUZZER_H \ No newline at end of file diff --git a/test/fuzztest/castsessionmanagerservicestub_fuzzer/project.xml b/test/fuzztest/castsessionmanagerservicestub_fuzzer/project.xml new file mode 100644 index 0000000..4fdbc40 --- /dev/null +++ b/test/fuzztest/castsessionmanagerservicestub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp b/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp new file mode 100644 index 0000000..107d57d --- /dev/null +++ b/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Add Token Fuzz. + * Author: renshuang + * Create: 2023-07-07 + */ + +#include "add_cast_engine_token_fuzzer.h" + +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +namespace OHOS { + +void AddCastEngineTokenFuzzer::AddCastEngineToken() +{ + constexpr int castFuzzPermissionNum = 2; + const char *perms[castFuzzPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, + .permsNum = castFuzzPermissionNum, + .aclsNum = 0, + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "cast_engine_fuzzer", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + SetSelfTokenID(tokenId); + Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); +} +} // namespace OHOS \ No newline at end of file diff --git a/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.h b/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.h new file mode 100644 index 0000000..ae9fa2a --- /dev/null +++ b/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Add Token Fuzz. + * Author: renshuang + * Create: 2023-07-07 + */ + +#ifndef ADD_CAST_ENGINE_TOKEN_FUZZER +#define ADD_CAST_ENGINE_TOKEN_FUZZER + +namespace OHOS { +class AddCastEngineTokenFuzzer { +public: + static void AddCastEngineToken(); +}; +} // namespace OHOS +#endif // ADD_CAST_ENGINE_TOKEN_FUZZER \ No newline at end of file diff --git a/test/fuzztest/streamplayerimplstub_fuzzer/BUILD.gn b/test/fuzztest/streamplayerimplstub_fuzzer/BUILD.gn new file mode 100644 index 0000000..c50907a --- /dev/null +++ b/test/fuzztest/streamplayerimplstub_fuzzer/BUILD.gn @@ -0,0 +1,69 @@ +# Copyright (c) 2023 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#####################hydra-fuzz################### +import("//build/config/features.gni") +import("//build/test.gni") + +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +##############################fuzztest########################################## +ohos_fuzztest("StreamPlayerImplStubFuzzTest") { + module_out_path = "cast_engine/cast_engine" + fuzz_config_file = "$cast_engine_root/test/fuzztest/streamplayerimplstub_fuzzer" + + include_dirs = [ + "include", + "$cast_engine_client/include", + "$cast_engine_common/include/private", + "$cast_engine_interfaces/inner_api/include", + "$cast_engine_root/test/fuzztest/common_fuzzer", + "${cast_session_stream_path}/src/channel/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/stream/src/local/include", + "${cast_session_stream_path}/src/stream/src/player/include", + ] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ + "stream_player_impl_stub_fuzzer.cpp", + "$cast_engine_root/test/fuzztest/common_fuzzer/add_cast_engine_token_fuzzer.cpp", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + ] + + external_deps = [ + "access_token:libaccesstoken_sdk", + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "c_utils:utils", + "hilog:libhilog", + "ipc:ipc_core", + "graphic_2d:surface" + ] +} +############################################################################### +group("fuzztest") { + testonly = true + deps = [] + deps += [ + ":StreamPlayerImplStubFuzzTest", + ] +} +############################################################################### diff --git a/test/fuzztest/streamplayerimplstub_fuzzer/project.xml b/test/fuzztest/streamplayerimplstub_fuzzer/project.xml new file mode 100644 index 0000000..4fdbc40 --- /dev/null +++ b/test/fuzztest/streamplayerimplstub_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.cpp b/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.cpp new file mode 100644 index 0000000..d3b63bd --- /dev/null +++ b/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.cpp @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: StreamPlayerImplStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-20 + */ + +#include "stream_player_impl_stub_fuzzer.h" + +#include + +#include "add_cast_engine_token_fuzzer.h" +#include "cast_engine_common.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "i_cast_local_file_channel.h" +#include "remote_player_controller.h" +#include "securec.h" +#include "stream_player_impl_stub.h" + +using namespace OHOS::CastEngine::CastEngineService; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-StreamPlayerImplStubFuzzer"); +namespace { +enum { + REGISTER_LISTENER = 1, + UNREGISTER_LISTENER, + SET_SURFACE, + PLAY_INDEX, + START, + PAUSE, + PLAY, + STOP, + NEXT, + PREVIOUS, + SEEK, + FAST_FORWARD, + FAST_REWIND, + SET_VOLUME, + SET_LOOP_MODE, + SET_SPEED, + GET_PLAYER_STATUS, + GET_POSITION, + GET_DURATION, + GET_VOLUME, + GET_LOOP_MODE, + GET_PLAY_SPEED, + GET_MEDIA_INFO_HOLDER, + RELEASE +}; +} // namespace + +int32_t StreamPlayerOnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply) +{ + auto fileChannel = std::make_shared(); + if (!fileChannel) { + CLOGE("fileChannel is null"); + return CAST_ENGINE_ERROR; + } + auto remotePlayer = std::make_shared(nullptr, fileChannel); + if (remotePlayer == nullptr) { + CLOGE("streamController is null"); + return CAST_ENGINE_ERROR; + } + sptr streamPlayerImplStub = new (std::nothrow) StreamPlayerImplStub(remotePlayer); + if (!streamPlayerImplStub) { + CLOGE("streamPlayerImplStub is null"); + return CAST_ENGINE_ERROR; + } + MessageOption option; + CLOGE("StreamPlayerOnRemoteRequest, code:%{public}d", code); + return streamPlayerImplStub->OnRemoteRequest(code, data, reply, option); +} + +int32_t UnregisterListenerFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size == 0)) { + return CAST_ENGINE_ERROR; + } + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(UNREGISTER_LISTENER, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t PlayIndexFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t index = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(index)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(PLAY_INDEX, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t PlayFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(PLAY, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t PauseFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(PAUSE, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t StopFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(STOP, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t NextFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(NEXT, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t PreviousFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(PREVIOUS, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SeekFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t position = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(position)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(SEEK, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t FastForwardFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t delta = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(delta)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(FAST_FORWARD, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t FastRewindFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t delta = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(delta)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(FAST_REWIND, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetVolumeFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t volume = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(volume)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(SET_VOLUME, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetLoopModeFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t mode = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(mode)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(SET_LOOP_MODE, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t SetSpeedFuzzTest(const uint8_t *data, size_t size) +{ + if ((data == nullptr) || (size < sizeof(int32_t))) { + return CAST_ENGINE_ERROR; + } + int32_t speed = *reinterpret_cast(data); + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (!dataParcel.WriteInt32(speed)) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(SET_SPEED, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetPlayerStatusFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_PLAYER_STATUS, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetPositionFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_POSITION, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetDurationFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_DURATION, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetVolumeFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_VOLUME, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetLoopModeFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_LOOP_MODE, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetPlaySpeedFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_PLAY_SPEED, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t GetMediaInfoHolderFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(GET_MEDIA_INFO_HOLDER, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + auto mediaInfos = ReadMediaInfoHolder(reply); + if (mediaInfos == nullptr) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} + +int32_t ReleaseFuzzTest(const uint8_t *data, size_t size) +{ + MessageParcel dataParcel; + MessageParcel reply; + if (!dataParcel.WriteInterfaceToken(StreamPlayerImplStub::GetDescriptor())) { + return CAST_ENGINE_ERROR; + } + if (StreamPlayerOnRemoteRequest(RELEASE, dataParcel, reply) != ERR_NONE) { + return CAST_ENGINE_ERROR; + } + + return reply.ReadInt32(); +} +} // CastEngineService +} // CastEngine +} // OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + OHOS::AddCastEngineTokenFuzzer::AddCastEngineToken(); + UnregisterListenerFuzzTest(data, size); + PlayIndexFuzzTest(data, size); + PlayFuzzTest(data, size); + PauseFuzzTest(data, size); + StopFuzzTest(data, size); + NextFuzzTest(data, size); + PreviousFuzzTest(data, size); + SeekFuzzTest(data, size); + SetVolumeFuzzTest(data, size); + SetLoopModeFuzzTest(data, size); + SetSpeedFuzzTest(data, size); + GetPlayerStatusFuzzTest(data, size); + GetPositionFuzzTest(data, size); + GetDurationFuzzTest(data, size); + GetVolumeFuzzTest(data, size); + GetLoopModeFuzzTest(data, size); + GetPlaySpeedFuzzTest(data, size); + GetMediaInfoHolderFuzzTest(data, size); + ReleaseFuzzTest(data, size); + return 0; +} diff --git a/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.h b/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.h new file mode 100644 index 0000000..10ba19c --- /dev/null +++ b/test/fuzztest/streamplayerimplstub_fuzzer/stream_player_impl_stub_fuzzer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: StreamPlayerImplStub OnRemoteRequest Fuzz. + * Author: renshuang + * Create: 2023-06-20 + */ + +#ifndef STREAM_PLAYER_IMPL_STUB_FUZZER_H +#define STREAM_PLAYER_IMPL_STUB_FUZZER_H + +#define FUZZ_PROJECT_NAME "streamplayerimplstub_fuzzer" + +#endif // STREAM_PLAYER_IMPL_STUB_FUZZER_H \ No newline at end of file diff --git a/test/unittest/phone/cast_session_manager_test.cpp b/test/unittest/phone/cast_session_manager_test.cpp new file mode 100644 index 0000000..9f0dd43 --- /dev/null +++ b/test/unittest/phone/cast_session_manager_test.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Connection Manager. + * Author: jiangfan + * Create: 2023-5-27 + */ + +#include +#include "gtest/gtest.h" +#include "cast_session_manager.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-SessionManager-Test"); + +class CastSessionManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastSessionManagerListener : public ICastSessionManagerListener { +public: + void OnDeviceFound(const std::vector &deviceList) override + { + static_cast(deviceList); + } + void OnSessionCreated(const std::shared_ptr &castSession) override + { + static_cast(castSession); + } + void OnServiceDied() override {} + void OnDeviceOffline(const std::string &deviceId) override + { + static_cast(deviceId); + } +}; + +namespace { + constexpr int PROTOCOLS = 1; +} + +void CastSessionManagerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "cast_session_manager_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); +} + +void CastSessionManagerTest::TearDownTestCase(void) {} +void CastSessionManagerTest::SetUp(void) +{ + /* Sleep 200ms */ + std::this_thread::sleep_for(std::chrono::milliseconds(200)); +} +void CastSessionManagerTest::TearDown(void) {} + +/** + * @tc.name: RegisterListenerTest_001 + * @tc.desc: Test the RegisterListener function. The empty listener is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, RegisterListenerTest_001, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_001"); + auto result = CastSessionManager::GetInstance().RegisterListener(nullptr); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: RegisterListenerTest_002 + * @tc.desc: Test the RegisterListener function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, RegisterListenerTest_002, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_002"); + auto listener = std::make_shared(); + auto result = CastSessionManager::GetInstance().RegisterListener(listener); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + CastSessionManager::GetInstance().Release(); +} + +/** + * @tc.name: UnregisterListenerTest_001 + * @tc.desc: Test the UnregisterListener function in the uninitialized condition. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, UnregisterListenerTest_001, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_001"); + auto result = CastSessionManager::GetInstance().UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: UnregisterListenerTest_002 + * @tc.desc: Test the UnregisterListener function return true. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, UnregisterListenerTest_002, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_002"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + auto result = CastSessionManager::GetInstance().UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: ReleaseTest_001 + * @tc.desc: Test the Release function in the uninitialized condition. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, ReleaseTest_001, TestSize.Level1) +{ + CLOGD("ReleaseTest_001"); + auto result = CastSessionManager::GetInstance().Release(); + EXPECT_EQ(result, ERR_NO_PERMISSION); +} + +/** + * @tc.name: ReleaseTest_002 + * @tc.desc: Test the Release function return true. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, ReleaseTest_002, TestSize.Level1) +{ + CLOGD("ReleaseTest_002"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + auto result = CastSessionManager::GetInstance().Release(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: CreateCastSessionTest_001 + * @tc.desc: Test the CreateCastSession function in the uninitialized condition. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, CreateCastSessionTest_001, TestSize.Level1) +{ + CLOGD("CreateCastSessionTest_001"); + std::shared_ptr castSession; + CastSessionManager::GetInstance().CreateCastSession(CastSessionProperty {}, castSession); + EXPECT_EQ(castSession, nullptr); +} + +/** + * @tc.name: CreateCastSessionTest_002 + * @tc.desc: Test the CreateCastSession function return non-empty. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, CreateCastSessionTest_002, TestSize.Level1) +{ + CLOGD("CreateCastSessionTest_002"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + std::shared_ptr castSession; + CastSessionManager::GetInstance().CreateCastSession(CastSessionProperty {}, castSession); + EXPECT_NE(castSession, nullptr); + CastSessionManager::GetInstance().Release(); +} + +/** + * @tc.name: StartDiscoveryTest_001 + * @tc.desc: Test the StartDiscovery function in the uninitialized condition. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, StartDiscoveryTest_001, TestSize.Level1) +{ + CLOGD("StartDiscoveryTest_001"); + auto result = CastSessionManager::GetInstance().StartDiscovery(PROTOCOLS); + EXPECT_EQ(result, ERR_NO_PERMISSION); +} + +/** + * @tc.name: StartDiscoveryTest_002 + * @tc.desc: Test the StartDiscovery function return true. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, StartDiscoveryTest_002, TestSize.Level1) +{ + CLOGD("StartDiscoveryTest_0200"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + auto result = CastSessionManager::GetInstance().StartDiscovery(PROTOCOLS); + CastSessionManager::GetInstance().StopDiscovery(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + CastSessionManager::GetInstance().Release(); +} + +/** + * @tc.name: SetDiscoverableTest_001 + * @tc.desc: Test the SetDiscoverable function return in the uninitialized condition. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, SetDiscoverableTest_001, TestSize.Level1) +{ + CLOGD("SetDiscoverableTest_001"); + auto result = CastSessionManager::GetInstance().SetDiscoverable(true); + EXPECT_EQ(result, ERR_NO_PERMISSION); +} + +/** + * @tc.name: SetDiscoverableTest_002 + * @tc.desc: Test the SetDiscoverable function return true. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, SetDiscoverableTest_002, TestSize.Level1) +{ + CLOGD("SetDiscoverableTest_002"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + auto result = CastSessionManager::GetInstance().SetDiscoverable(true); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + CastSessionManager::GetInstance().SetDiscoverable(false); + CastSessionManager::GetInstance().Release(); +} + +/** + * @tc.name: SetDiscoverableTest_003 + * @tc.desc: Test the SetDiscoverable function return true. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionManagerTest, SetDiscoverableTest_003, TestSize.Level1) +{ + CLOGD("SetDiscoverableTest_003"); + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + auto result = CastSessionManager::GetInstance().SetDiscoverable(false); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + CastSessionManager::GetInstance().Release(); +} +} +} +} diff --git a/test/unittest/phone/cast_session_test.cpp b/test/unittest/phone/cast_session_test.cpp new file mode 100644 index 0000000..f5c4c65 --- /dev/null +++ b/test/unittest/phone/cast_session_test.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Cast Session. + * Author: jiangfan + * Create: 2023-6-1 + */ + +#include "gtest/gtest.h" +#include "cast_device_data_manager.h" +#include "cast_engine_log.h" +#include "cast_engine_errors.h" +#include "cast_engine_common.h" +#include "cast_session_manager.h" +#include "mirror_player.h" +#include "stream_player.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; +using OHOS::CastEngine::CastEngineService::CastDeviceDataManager; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Cast-Session-Test"); + +class CastSessionTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastSessionManagerListener : public ICastSessionManagerListener { +public: + void OnDeviceFound(const std::vector &deviceList) override + { + static_cast(deviceList); + } + void OnSessionCreated(const std::shared_ptr &castSession) override + { + static_cast(castSession); + } + void OnServiceDied() override {} + void OnDeviceOffline(const std::string &deviceId) override + { + static_cast(deviceId); + } +}; + +class TestCastSessionListener : public ICastSessionListener { +public: + void OnDeviceState(const DeviceStateInfo &stateInfo) override + { + static_cast(stateInfo); + } + void OnEvent(const EventId &eventId, const std::string &jsonParam) override + { + static_cast(eventId); + static_cast(jsonParam); + } +}; + +class TestDataTransListener : public IDataTransListener { +public: + void OnBytesReceived(const uint8_t *data, uint32_t len) override {} + void OnFilesSent(std::string firstFile, int percent) override {} + void OnFilesReceived(std::string firstFile, int percent, const RcvFdFileMap &fdMap) override {} +}; + +namespace { +std::shared_ptr CreateSession() +{ + std::shared_ptr session; + auto listener = std::make_shared(); + CastSessionManager::GetInstance().RegisterListener(listener); + CastSessionManager::GetInstance().CreateCastSession(CastSessionProperty {}, session); + return session; +} +} + +void CastSessionTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = NULL, + .perms = perms, + .acls = NULL, + .processName = "cast_session_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); +} + +void CastSessionTest::TearDownTestCase(void) {} +void CastSessionTest::SetUp(void) +{ + /* Sleep 200ms */ + std::this_thread::sleep_for(std::chrono::milliseconds(200)); +} + +void CastSessionTest::TearDown(void) +{ + CastSessionManager::GetInstance().Release(); +} + +/** + * @tc.name: RegisterListenerTest_001 + * @tc.desc: Test the RegisterListener function. The empty listener is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, RegisterListenerTest_001, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + auto result = session->RegisterListener(nullptr); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: RegisterListenerTest_002 + * @tc.desc: Test the RegisterListener function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, RegisterListenerTest_002, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + auto result = session->RegisterListener(std::make_shared()); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: AddDeviceTest_001 + * @tc.desc: Test the AddDevice function. The empty remoteDevice is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, AddDeviceTest_001, TestSize.Level1) +{ + CLOGD("AddDeviceTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + auto result = session->AddDevice(CastRemoteDevice{}); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: AddDeviceTest_002 + * @tc.desc: Test the AddDevice function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, AddDeviceTest_002, TestSize.Level1) +{ + CLOGD("AddDeviceTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + CastRemoteDevice remoteDevice{}; + remoteDevice.deviceId = "AddDeviceTest_002"; + auto result = session->AddDevice(remoteDevice); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + session->Release(); +} + +/** + * @tc.name: AddDeviceTest_003 + * @tc.desc: Test the AddDevice function.Add a device that does not exist. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, AddDeviceTest_003, TestSize.Level1) +{ + CLOGD("AddDeviceTest_003"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + CastRemoteDevice remoteDevice{}; + remoteDevice.deviceId = "AddDeviceTest_003"; + auto result = session->AddDevice(remoteDevice); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + session->Release(); +} + +/** + * @tc.name: RemoveDeviceTest_001 + * @tc.desc: Test the RemoveDevice function. The empty remoteDevice is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, RemoveDeviceTest_001, TestSize.Level1) +{ + CLOGD("RemoveDeviceTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + auto result = session->AddDevice(CastRemoteDevice {}); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: RemoveDeviceTest_002 + * @tc.desc: Test the RemoveDevice function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, RemoveDeviceTest_002, TestSize.Level1) +{ + CLOGD("RemoveDeviceTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + CastRemoteDevice remoteDevice{}; + remoteDevice.deviceId = "RemoveDeviceTest_002"; + session->AddDevice(remoteDevice); + auto result = session->RemoveDevice(remoteDevice.deviceId); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: StartAuthTest_001 + * @tc.desc: Test the StartAuth function. The empty authInfo is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, StartAuthTest_001, TestSize.Level1) +{ + CLOGD("StartAuthTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + auto result = session->StartAuth(AuthInfo {}); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: StartAuthTest_002 + * @tc.desc: Test the StartAuth function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, StartAuthTest_002, TestSize.Level1) +{ + CLOGD("StartAuthTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + AuthInfo authInfo; + authInfo.deviceId = "StartAuthTest_002"; + CastSessionManager::GetInstance().Release(); + auto result = session->StartAuth(authInfo); + EXPECT_EQ(result, ERR_NO_PERMISSION); + session->Release(); +} + +/** + * @tc.name: StartAuthTest_003 + * @tc.desc: Test the StartAuth function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, StartAuthTest_003, TestSize.Level1) +{ + CLOGD("StartAuthTest_003"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + AuthInfo authInfo; + authInfo.deviceId = "StartAuthTest_003"; + auto result = session->StartAuth(authInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + session->Release(); +} + +/** + * @tc.name: GetSessionIdTest_001 + * @tc.desc: Test the GetSessionId function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, GetSessionIdTest_001, TestSize.Level1) +{ + CLOGD("GetSessionIdTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + string sessionId; + CastSessionManager::GetInstance().Release(); + auto result = session->GetSessionId(sessionId); + EXPECT_EQ(result, ERR_NO_PERMISSION); +} + +/** + * @tc.name: GetSessionIdTest_002 + * @tc.desc: Test the GetSessionId function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, GetSessionIdTest_002, TestSize.Level1) +{ + CLOGD("GetSessionIdTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + string sessionId; + auto result = session->GetSessionId(sessionId); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: SetSessionPropertyTest_001 + * @tc.desc: Test the SetSessionProperty function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, SetSessionPropertyTest_001, TestSize.Level1) +{ + CLOGD("SetSessionPropertyTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + auto result = session->SetSessionProperty(CastSessionProperty {}); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: CreateMirrorPlayerTest_001 + * @tc.desc: Test the CreateMirrorPlayer function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, CreateMirrorPlayerTest_001, TestSize.Level1) +{ + CLOGD("CreateMirrorPlayerTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + std::shared_ptr mirrorPlayer; + auto result = session->CreateMirrorPlayer(mirrorPlayer); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: CreateStreamPlayerTest_001 + * @tc.desc: Test the CreateStreamPlayer function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, CreateStreamPlayerTest_001, TestSize.Level1) +{ + CLOGD("CreateStreamPlayerTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + std::shared_ptr streamPlayer; + session->RegisterListener(std::make_shared()); + auto result = session->CreateStreamPlayer(streamPlayer); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + session->Release(); +} + +/** + * @tc.name: ReleaseTest_001 + * @tc.desc: Test the Release function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, ReleaseTest_001, TestSize.Level1) +{ + CLOGD("ReleaseTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + auto result = session->Release(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SendBytesTest_001 + * @tc.desc: Test the SendBytes function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, SetCastModeTest_001, TestSize.Level1) +{ + CLOGD("SetCastModeTest_001"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + string jsonParam = "SetCastModeTest_001"; + CastSessionManager::GetInstance().Release(); + auto result = session->SetCastMode(CastMode {}, jsonParam); + EXPECT_EQ(result, ERR_NO_PERMISSION); +} + +/** + * @tc.name: SendBytesTest_002 + * @tc.desc: Test the SendBytes function. + * @tc.type: FUNC + */ +HWTEST_F(CastSessionTest, SetCastModeTest_002, TestSize.Level1) +{ + CLOGD("SendBytesTest_002"); + std::shared_ptr session = CreateSession(); + ASSERT_NE(session, nullptr); + session->RegisterListener(std::make_shared()); + string jsonParam = "SetCastModeTest_001"; + auto result = session->SetCastMode(CastMode {}, jsonParam); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} +} +} +} diff --git a/test/unittest/phone/stream/BUILD.gn b/test/unittest/phone/stream/BUILD.gn new file mode 100644 index 0000000..7efa27c --- /dev/null +++ b/test/unittest/phone/stream/BUILD.gn @@ -0,0 +1,405 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved. + +import("//build/ohos.gni") +import("//build/ohos_var.gni") +import("//build/test.gni") +import("//foundation/CastEngine/castengine_cast_framework/cast_engine.gni") + +config("cast_session_config") { + include_dirs = [ + "${cast_engine_interfaces}/inner_api", + "${cast_engine_interfaces}/inner_api/include", + "//base/security/access_token/interfaces/innerkits/nativetoken/include", + "//base/security/access_token/interfaces/innerkits/accesstoken/include", + "//base/security/access_token/interfaces/innerkits/token_setproc/include", + ] +} + +ohos_unittest("cast_stream_player_manager_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "cast_stream_player_manager_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("stream_player_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "stream_player_test.cpp", + "${cast_engine_client}/src/stream_player.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_engine_common}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_interfaces}/inner_api:cast_engine_client", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("remote_player_controller_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "remote_player_controller_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("cast_stream_manager_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "cast_stream_manager_client_test.cpp", + "cast_stream_manager_server_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("stream_player_impl_stub_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "stream_player_impl_stub_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + "//foundation/graphic/graphic_2d/rosen/modules/platform/ipc_core" + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("cast_stream_player_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "cast_stream_player_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +ohos_unittest("stream_player_listener_impl_stub_test") { + module_out_path = "cast_engine/cast_engine/stream/" + + testonly = true + + sources = [ + "stream_player_listener_impl_stub_test.cpp", + "${cast_engine_client}/src/stream_player_listener_impl_stub.cpp" + ] + + configs = [ + ":cast_session_config" + ] + + cflags_cc = [ + "--coverage" + ] + + ldflags = [ + "--coverage", + ] + + include_dirs = [ + "${cast_engine_client}/include", + "${cast_session_stream_path}/src/stream/include", + "${cast_session_stream_path}/src/channel/include", + "//foundation/graphic/graphic_2d/frameworks/surface/include", + "//foundation/graphic/graphic_2d/interfaces/inner_api/surface", + ] + + deps = [ + "${cast_session_stream_path}/src/stream:cast_session_stream", + "${cast_engine_client}:cast_client_inner", + "${cast_engine_common}:cast_engine_common_sources", + ] + + external_deps = [ + "access_token:libnativetoken", + "access_token:libtoken_setproc", + "access_token:libaccesstoken_sdk", + "audio_framework:audio_client", + "c_utils:utils", + "googletest:gtest", + "graphic_2d:surface", + "hilog:libhilog", + "ipc:ipc_core", + "player_framework:media_client", + ] + + subsystem_name = "castplus" + part_name = "cast_engine" +} + +group("stream_unittest") { + testonly = true + deps = [ + ":cast_stream_manager_test", + ":cast_stream_player_test", + ":cast_stream_player_manager_test", + ":remote_player_controller_test", + ":stream_player_test", + ":stream_player_listener_impl_stub_test" + ] +} \ No newline at end of file diff --git a/test/unittest/phone/stream/cast_stream_manager_test.cpp b/test/unittest/phone/stream/cast_stream_manager_test.cpp new file mode 100644 index 0000000..0d251b2 --- /dev/null +++ b/test/unittest/phone/stream/cast_stream_manager_test.cpp @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Connection Manager. + * Author: jiangfan + * Create: 2023-6-9 + */ + +#include "gtest/gtest.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_stream_manager.h" +#include "i_cast_stream_manager.h" +#include "stream_player_listener_impl_stub.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; +using OHOS::CastEngine::CastEngineClient::StreamPlayerListenerImplStub; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Stream-Player-Manager-Test"); + +using nlohmann::json; + +class CastStreamManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastStreamListener : public ICastStreamListener { +public: + bool SendActionToPeers(int action, const std::string ¶m) override + { + return true; + } + void OnRenderReady(bool isReady) override {} + void OnEvent(EventId eventId, const std::string &data) override {} +}; + +namespace { +std::shared_ptr CreateCastStreamManager() +{ + auto listener = std::make_shared(); + EndType endType; + return std::make_shared(listener, endType); +} +} + +void CastStreamManagerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "cast_stream_manager_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); +} + +void CastStreamManagerTest::TearDownTestCase(void) {} +void CastStreamManagerTest::SetUp(void) {} +void CastStreamManagerTest::TearDown(void) {} + +/** + * @tc.name: ProcessActionsEventTest_001 + * @tc.desc: Test the ProcessActionsEvent function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, ProcessActionsEventTest_001, TestSize.Level1) +{ + CLOGD("ProcessActionsEventTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + std::string param = "ProcessActionsEventTest_001"; + castStreamManager->ProcessActionsEvent(CastStreamManager::MODULE_EVENT_ID_CONTROL_EVENT, param); +} + +/** + * @tc.name: NotifyPeerNextTest_001 + * @tc.desc: Test the NotifyPeerNext function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerNextTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerNextTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerNext(); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPreviousTest_001 + * @tc.desc: Test the NotifyPeerPrevious function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPreviousTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPreviousTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerPrevious(); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerNextRequestTest_001 + * @tc.desc: Test the NotifyPeerNextRequest function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerNextRequestTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerNextRequestTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerNextRequest(); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPreviousRequestTest_001 + * @tc.desc: Test the NotifyPeerPreviousRequest function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPreviousRequestTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPreviousRequestTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerPreviousRequest(); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerSeekDoneTest_001 + * @tc.desc: Test the NotifyPeerSeekDone function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerSeekDoneTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerSeekDoneTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + int position = 0; // start position + auto result = castStreamManager->NotifyPeerSeekDone(position); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPlayerStatusChangedTest_001 + * @tc.desc: Test the NotifyPeerPlayerStatusChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPlayerStatusChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPlayerStatusChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerPlayerStatusChanged(PlayerStates::PLAYER_STATE_ERROR, true); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPositionChangedTest_001 + * @tc.desc: Test the NotifyPeerPositionChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPositionChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPositionChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + int position = 0; + int bufferPosition = 0; + int duration = 0; + auto result = castStreamManager->NotifyPeerPositionChanged(position, bufferPosition, duration); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerMediaItemChangedTest_001 + * @tc.desc: Test the NotifyPeerMediaItemChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerMediaItemChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerMediaItemChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + MediaInfo mediaInfo{"NotifyPeerMediaItemChangedTest_001", "NotifyPeerMediaItemChangedTest_001"}; + auto result = castStreamManager->NotifyPeerMediaItemChanged(mediaInfo); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerVolumeChangedTest_001 + * @tc.desc: Test the NotifyPeerVolumeChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerVolumeChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerVolumeChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + int volume = 0; + int maxVolume = 0; + auto result = castStreamManager->NotifyPeerVolumeChanged(volume, maxVolume); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerRepeatModeChangedTest_001 + * @tc.desc: Test the NotifyPeerRepeatModeChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerRepeatModeChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerRepeatModeChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerRepeatModeChanged(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPlaySpeedChangedTest_001 + * @tc.desc: Test the NotifyPeerPlaySpeedChanged function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPlaySpeedChangedTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPlaySpeedChangedTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerPlaySpeedChanged(PlaybackSpeed::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerPlayerErrorTest_001 + * @tc.desc: Test the NotifyPeerPlayerError function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerPlayerErrorTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerPlayerErrorTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + int errCode = CAST_ENGINE_ERROR; + std::string errMsg; + auto result = castStreamManager->NotifyPeerPlayerError(errCode, errMsg); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerCreateChannelTest_001 + * @tc.desc: Test the NotifyPeerCreateChannel function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerCreateChannelTest_001, TestSize.Level1) +{ + CLOGD("NotifyPeerCreateChannelTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerCreateChannel(); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: NotifyPeerCreateChannelTest_002 + * @tc.desc: Test the NotifyPeerCreateChannel function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, NotifyPeerCreateChannelTest_002, TestSize.Level1) +{ + CLOGD("NotifyPeerCreateChannelTest_002"); + EndType endType; + auto castStreamManager = std::make_shared(nullptr, endType); + ASSERT_NE(castStreamManager, nullptr); + auto result = castStreamManager->NotifyPeerCreateChannel(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: OnEventTest_001 + * @tc.desc: Test the OnEvent function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, OnEventTest_001, TestSize.Level1) +{ + CLOGD("OnEventTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + std::string data; + castStreamManager->OnEvent(EventId::EVENT_BEGIN, data); +} + +/** + * @tc.name: OnEventTest_002 + * @tc.desc: Test the OnEvent function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, OnEventTest_002, TestSize.Level1) +{ + CLOGD("OnEventTest_002"); + EndType endType; + auto castStreamManager = std::make_shared(nullptr, endType); + ASSERT_NE(castStreamManager, nullptr); + std::string data; + castStreamManager->OnEvent(EventId::EVENT_BEGIN, data); +} + +/** + * @tc.name: OnRenderReadyTest_001 + * @tc.desc: Test the OnRenderReady function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamManagerTest, OnRenderReadyTest_001, TestSize.Level1) +{ + CLOGD("OnRenderReadyTest_001"); + auto castStreamManager = CreateCastStreamManager(); + ASSERT_NE(castStreamManager, nullptr); + castStreamManager->OnRenderReady(true); +} +} +} +} \ No newline at end of file diff --git a/test/unittest/phone/stream/cast_stream_player_manager_test.cpp b/test/unittest/phone/stream/cast_stream_player_manager_test.cpp new file mode 100644 index 0000000..6973e75 --- /dev/null +++ b/test/unittest/phone/stream/cast_stream_player_manager_test.cpp @@ -0,0 +1,808 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Connection Manager. + * Author: jiangfan + * Create: 2023-6-9 + */ + +#include +#include +#include +#include "gtest/gtest.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "cast_stream_player_manager.h" +#include "cast_stream_manager_server.h" +#include "stream_player_listener_impl_stub.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; +using OHOS::CastEngine::CastEngineClient::StreamPlayerListenerImplStub; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Stream-Player-Manager-Test"); + +class CastStreamPlayerManagerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class BufferConsumerListener : public ::OHOS::IBufferConsumerListener { +public: + void OnBufferAvailable() override {} +}; + +namespace { +sptr listenerStub; + +std::shared_ptr CreateStreamPlayManager() +{ + std::shared_ptr callback; + std::shared_ptr fileChannel; + return std::make_shared(callback, fileChannel); +} + +sptr CreateProducer() +{ + sptr consSurface; + sptr producer; + consSurface = IConsumerSurface::Create(); + if (!consSurface) { + return nullptr; + } + sptr surfaceListener = new BufferConsumerListener(); + if (!surfaceListener) { + return nullptr; + } + consSurface->RegisterConsumerListener(surfaceListener); + producer = consSurface->GetProducer(); + return producer; +} + +void ReleaseCallback() +{ + CLOGD("Release Callback"); +} +} + +void CastStreamPlayerManagerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "cast_stream_player_manager_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); + listenerStub = new (std::nothrow) StreamPlayerListenerImplStub(nullptr); + ASSERT_NE(listenerStub, nullptr); +} + +void CastStreamPlayerManagerTest::TearDownTestCase(void) {} +void CastStreamPlayerManagerTest::SetUp(void) {} +void CastStreamPlayerManagerTest::TearDown(void) {} + +/** + * @tc.name: RegisterListenerTest_001 + * @tc.desc: Test the RegisterListener function. The empty listener is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, RegisterListenerTest_001, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->RegisterListener(nullptr); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: RegisterListenerTest_002 + * @tc.desc: Test the RegisterListener function.Transfer non-null listener deregistration. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, RegisterListenerTest_002, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->RegisterListener(listenerStub); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->UnregisterListener(); +} + +/** + * @tc.name: UnregisterListenerTest_001 + * @tc.desc: Test the UnregisterListener function.Unregistered interception. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, UnregisterListenerTest_001, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SetSurfaceTest_001 + * @tc.desc: Test the SetSurface function.The input surface produce is empty. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetSurfaceTest_001, TestSize.Level1) +{ + CLOGD("SetSurfaceTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + streamPlayManager->RegisterListener(listenerStub); + auto result = streamPlayManager->SetSurface(nullptr); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SetSurfaceTest_002 + * @tc.desc: Test the SetSurface function.Construction surface produce. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetSurfaceTest_002, TestSize.Level1) +{ + CLOGD("SetSurfaceTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + streamPlayManager->RegisterListener(listenerStub); + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + auto result = streamPlayManager->SetSurface(producer); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: LoadTest_001 + * @tc.desc: Test the Load function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, LoadTest_001, TestSize.Level1) +{ + CLOGD("LoadTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"LoadTest_001", "LoadTest_001"}; + auto result = streamPlayManager->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: PlayTest_001 + * @tc.desc: Test the Play function.The input non-boundary value. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_001, TestSize.Level1) +{ + CLOGD("PlayTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int index = 1; // non-boundary value + auto result = streamPlayManager->Play(index); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: PlayTest_002 + * @tc.desc: Test the Play function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_002, TestSize.Level1) +{ + CLOGD("PlayTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"PlayTest_002", "PlayTest_002"}; + auto result = streamPlayManager->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: PlayTest_003 + * @tc.desc: Test the Play function.The input mediaUrl is not empty. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_003, TestSize.Level1) +{ + CLOGD("PlayTest_003"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"PlayTest_003", "PlayTest_003"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + auto result = streamPlayManager->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_004, TestSize.Level1) +{ + CLOGD("PlayTest_004"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"PlayTest_004", "PlayTest_004", "http://PlayTest_004"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + auto result = streamPlayManager->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: PlayTest_005 + * @tc.desc: Test the Play function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_005, TestSize.Level1) +{ + CLOGD("PlayTest_005"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Play(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: PlayTest_006 + * @tc.desc: Test the Play function.Prerequisite: Playable. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PlayTest_006, TestSize.Level1) +{ + CLOGD("PlayTest_006"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"PlayTest_006", "PlayTest_006", "http://PlayTest_006"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + streamPlayManager->Pause(); + auto result = streamPlayManager->Play(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: PauseTest_001 + * @tc.desc: Test the Pause function.Cannot pause when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PauseTest_001, TestSize.Level1) +{ + CLOGD("PauseTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Pause(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: PauseTest_002 + * @tc.desc: Test the Pause function.When playing, can pause it. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PauseTest_002, TestSize.Level1) +{ + CLOGD("PauseTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"PauseTest_002", "PauseTest_002", "http://PauseTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + auto result = streamPlayManager->Pause(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: StopTest_001 + * @tc.desc: Test the Stop function.Cannot stop when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, StopTest_001, TestSize.Level1) +{ + CLOGD("StopTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Stop(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: StopTest_002 + * @tc.desc: Test the Stop function.When playing, can stop it. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, StopTest_002, TestSize.Level1) +{ + CLOGD("StopTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"StopTest_002", "StopTest_002", "http://StopTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + auto result = streamPlayManager->Stop(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: NextTest_001 + * @tc.desc: Test the Next function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, NextTest_001, TestSize.Level1) +{ + CLOGD("NextTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Next(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: PreviousTest_001 + * @tc.desc: Test the Previous function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, PreviousTest_001, TestSize.Level1) +{ + CLOGD("PreviousTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Previous(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: SeekTest_001 + * @tc.desc: Test the Seek function.Cannot seek position when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SeekTest_001, TestSize.Level1) +{ + CLOGD("SeekTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int position = 0; + auto result = streamPlayManager->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: SeekTest_002 + * @tc.desc: Test the Seek function.When playing, can seek position. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SeekTest_002, TestSize.Level1) +{ + CLOGD("SeekTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"SeekTest_002", "SeekTest_002", "http://SeekTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int position = 0; + auto result = streamPlayManager->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastForwardTest_001 + * @tc.desc: Test the FastForward function.Cannot fastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastForwardTest_001, TestSize.Level1) +{ + CLOGD("FastForwardTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"FastForwardTest_001", "FastForwardTest_001", "http://FastForwardTest_001"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int delta = 1000; + auto result = streamPlayManager->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastForwardTest_002 + * @tc.desc: Test the FastForward function.Cannot fastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastForwardTest_002, TestSize.Level1) +{ + CLOGD("FastForwardTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"FastForwardTest_002", "FastForwardTest_002", "http://FastForwardTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int delta = -1000; + auto result = streamPlayManager->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastForwardTest_003 + * @tc.desc: Test the FastForward function.Cannot fastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastForwardTest_003, TestSize.Level1) +{ + CLOGD("FastForwardTest_003"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int delta = 1000; + auto result = streamPlayManager->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastRewindTest_001 + * @tc.desc: Test the FastRewind function.Cannot fastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastRewindTest_001, TestSize.Level1) +{ + CLOGD("FastRewindTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"FastRewindTest_001", "FastRewindTest_001", "http://FastRewindTest_001"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int delta = 1000; + auto result = streamPlayManager->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastRewindTest_002 + * @tc.desc: Test the FastRewind function.Cannot FastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastRewindTest_002, TestSize.Level1) +{ + CLOGD("FastRewindTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"FastRewindTest_002", "FastRewindTest_002", "http://FastRewindTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int delta = -1000; + auto result = streamPlayManager->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: FastRewindTest_003 + * @tc.desc: Test the FastRewind function.Cannot FastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, FastRewindTest_003, TestSize.Level1) +{ + CLOGD("FastRewindTest_003"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int delta = 1000; + auto result = streamPlayManager->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: SetVolumeTest_001 + * @tc.desc: Test the SetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetVolumeTest_001, TestSize.Level1) +{ + CLOGD("SetVolumeTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int volume = 0; // Normal Value + auto result = streamPlayManager->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: SetLoopModeTest_001 + * @tc.desc: Test the SetLoopMode function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetVolumeTest_002, TestSize.Level1) +{ + CLOGD("SetVolumeTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int volume = 200; // Abnormal data + auto result = streamPlayManager->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: SetLoopModeTest_001 + * @tc.desc: Test the SetLoopMode function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("SetLoopModeTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->SetLoopMode(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: SetSpeedTest_001 + * @tc.desc: Test the SetSpeed function.Cannot set speed when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetSpeedTest_001, TestSize.Level1) +{ + CLOGD("SetSpeedTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->SetSpeed(PlaybackSpeed::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: SetSpeedTest_002 + * @tc.desc: Test the SetSpeed function.When playing, can set speed position. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, SetSpeedTest_002, TestSize.Level1) +{ + CLOGD("SetSpeedTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"SetSpeedTest_002", "SetSpeedTest_002", "http://SetSpeedTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + auto result = streamPlayManager->SetSpeed(PlaybackSpeed::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetPlayerStatusTest_001 + * @tc.desc: Test the GetPlayerStatus function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetPlayerStatusTest_001, TestSize.Level1) +{ + CLOGD("GetPlayerStatusTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + PlayerStates playerStates; + auto result = streamPlayManager->GetPlayerStatus(playerStates); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetPositionTest_001 + * @tc.desc: Test the GetPosition function.Cannot get position when not playing. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetPositionTest_001, TestSize.Level1) +{ + CLOGD("GetPositionTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int position; + auto result = streamPlayManager->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetPositionTest_002 + * @tc.desc: Test the GetPosition function.When playing, can get position. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetPositionTest_002, TestSize.Level1) +{ + CLOGD("GetPositionTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"GetPositionTest_002", "GetPositionTest_002", "http://GetPositionTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + int position; + auto result = streamPlayManager->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetDurationTest_001 + * @tc.desc: Test the GetDuration function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetDurationTest_001, TestSize.Level1) +{ + CLOGD("GetDurationTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int duration; + auto result = streamPlayManager->GetDuration(duration); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetVolumeTest_001 + * @tc.desc: Test the GetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetVolumeTest_001, TestSize.Level1) +{ + CLOGD("GetVolumeTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + int volume; + int maxVolume; + auto result = streamPlayManager->GetVolume(volume, maxVolume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetLoopModeTest_001 + * @tc.desc: Test the GetLoopMode function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("GetLoopModeTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + LoopMode sequence = LoopMode::LOOP_MODE_SEQUENCE; + auto result = streamPlayManager->GetLoopMode(sequence); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetMediaInfoHolderTest_001 + * @tc.desc: Test the GetMediaInfoHolder function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetPlaySpeedTest_001, TestSize.Level1) +{ + CLOGD("GetPlaySpeedTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + PlaybackSpeed playbackSpeed; + auto result = streamPlayManager->GetPlaySpeed(playbackSpeed); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + streamPlayManager->Release(); +} + +/** + * @tc.name: GetMediaInfoHolderTest_001 + * @tc.desc: Test the GetMediaInfoHolder function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, GetMediaInfoHolderTest_001, TestSize.Level1) +{ + CLOGD("GetMediaInfoHolderTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfoHolder mediaInfoHolder; + auto result = streamPlayManager->GetMediaInfoHolder(mediaInfoHolder); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + streamPlayManager->Release(); +} + +/** + * @tc.name: ReleaseTest_001 + * @tc.desc: Test the Release function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, ReleaseTest_001, TestSize.Level1) +{ + CLOGD("ReleaseTest_001"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + auto result = streamPlayManager->Release(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: ReleaseTest_002 + * @tc.desc: Test the Release function.Setting Callback in Advance. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerManagerTest, ReleaseTest_002, TestSize.Level1) +{ + CLOGD("ReleaseTest_002"); + std::shared_ptr streamPlayManager = CreateStreamPlayManager(); + ASSERT_NE(streamPlayManager, nullptr); + MediaInfo mediaInfo{"ReleaseTest_002", "ReleaseTest_002", "http://ReleaseTest_002"}; + auto producer = CreateProducer(); + ASSERT_NE(producer, nullptr); + streamPlayManager->SetSurface(producer); + streamPlayManager->Play(mediaInfo); + streamPlayManager->SetSessionCallbackForRelease(ReleaseCallback); + auto result = streamPlayManager->Release(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} +} +} +} \ No newline at end of file diff --git a/test/unittest/phone/stream/cast_stream_player_test.cpp b/test/unittest/phone/stream/cast_stream_player_test.cpp new file mode 100644 index 0000000..6ec41e0 --- /dev/null +++ b/test/unittest/phone/stream/cast_stream_player_test.cpp @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test cast_stream_player. + * Author: jiangfan + * Create: 2023-7-3 + */ + +#include +#include +#include +#include "gtest/gtest.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "cast_stream_common.h" +#include "cast_stream_player.h" +#include "cast_stream_player_utils.h" +#include "cast_stream_manager_server.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Cast-Stream-Player-Manager-Test"); + +class CastStreamPlayerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastStreamListener : public ICastStreamListener { +public: + bool SendActionToPeers(int action, const std::string ¶m) override + { + return true; + } + void OnRenderReady(bool isReady) override {} + void OnEvent(EventId eventId, const std::string &data) override {} +}; + +namespace { +std::shared_ptr CreateCallback() +{ + auto listener = std::make_shared(); + auto castStreamManager = std::make_shared(listener); + return std::make_shared(castStreamManager); +} + +std::shared_ptr CreateStreamPlayer() +{ + auto listener = std::make_shared(); + auto castStreamManager = std::make_shared(listener); + auto callback = std::make_shared(castStreamManager); + return std::make_shared(callback, nullptr); +} +} + +void CastStreamPlayerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "cast_stream_player_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %lu", tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); +} + +void CastStreamPlayerTest::TearDownTestCase(void) {} +void CastStreamPlayerTest::SetUp(void) {} +void CastStreamPlayerTest::TearDown(void) {} + +/** + * @tc.name: GetSpeedModeTest_001 + * @tc.desc: Test the GetSpeedMode function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetSpeedModeTest_001, TestSize.Level1) +{ + CLOGD("GetSpeedModeTest_001"); + auto castCallback = CreateCallback(); + ASSERT_NE(castCallback, nullptr); + castCallback->SetSpeedMode(Media::SPEED_FORWARD_0_75_X); + auto result = castCallback->GetSpeedMode(); + EXPECT_EQ(result, Media::SPEED_FORWARD_0_75_X); +} + +/** + * @tc.name: SetSwitchingTest_001 + * @tc.desc: Test the SetSwitching function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetSwitchingTest_001, TestSize.Level1) +{ + CLOGD("SetSwitchingTest_001"); + auto castCallback = CreateCallback(); + ASSERT_NE(castCallback, nullptr); + int switchingCount = 0; + castCallback->SetSwitching(); + auto result = castCallback->GetSwitching(); + EXPECT_NE(result, switchingCount); +} + +/** + * @tc.name: PrepareAsyncTest_001 + * @tc.desc: Test the PrepareAsync function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, PrepareAsyncTest_001, TestSize.Level1) +{ + CLOGD("PrepareAsyncTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->PrepareAsync(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: PauseTest_001 + * @tc.desc: Test the Pause function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, PauseTest_001, TestSize.Level1) +{ + CLOGD("PauseTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->Pause(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: StopTest_001 + * @tc.desc: Test the Stop function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, StopTest_001, TestSize.Level1) +{ + CLOGD("StopTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->Stop(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: ResetTest_001 + * @tc.desc: Test the Reset function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, ResetTest_001, TestSize.Level1) +{ + CLOGD("ResetTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->Reset(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: SetVolumeTest_001 + * @tc.desc: Test the SetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetVolumeTest_001, TestSize.Level1) +{ + CLOGD("SetVolumeTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + int volume = 0; // Normal Value + auto result = streamPlayer->SetVolume(volume); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: SetVolumeTest_002 + * @tc.desc: Test the SetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetVolumeTest_002, TestSize.Level1) +{ + CLOGD("SetVolumeTest_002"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + int volume = 500; // boundary value + auto result = streamPlayer->SetVolume(volume); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetVolumeTest_001 + * @tc.desc: Test the GetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetVolumeTest_001, TestSize.Level1) +{ + CLOGD("GetVolumeTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + int volume; + int maxVolume; + auto result = streamPlayer->GetVolume(volume, maxVolume); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: GetVolumeTest_002 + * @tc.desc: Test the GetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetVolumeTest_002, TestSize.Level1) +{ + CLOGD("GetVolumeTest_002"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + int maxVolume = CastStreamPlayerUtils::GetMaxVolume(); + EXPECT_NE(maxVolume, 0); + int curVolume = CastStreamPlayerUtils::GetVolume(); + EXPECT_NE(curVolume, 0); +} + + +/** + * @tc.name: SetLoopingTest_001 + * @tc.desc: Test the SetLooping function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetLoopingTest_001, TestSize.Level1) +{ + CLOGD("SetLoopingTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->SetLooping(true); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: SetLoopingTest_002 + * @tc.desc: Test the SetLooping function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetLoopingTest_002, TestSize.Level1) +{ + CLOGD("SetLoopingTest_002"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->SetLooping(false); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: GetCurrentTimeTest_001 + * @tc.desc: Test the GetCurrentTime function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetCurrentTimeTest_001, TestSize.Level1) +{ + CLOGD("GetCurrentTimeTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + int32_t currentTime; + auto result = streamPlayer->GetCurrentTime(currentTime); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetVideoTrackInfoTest_001 + * @tc.desc: Test the GetVideoTrackInfo function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetVideoTrackInfoTest_001, TestSize.Level1) +{ + CLOGD("GetVideoTrackInfoTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + std::vector videoTrack; + auto result = streamPlayer->GetVideoTrackInfo(videoTrack); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetAudioTrackInfoTest_001 + * @tc.desc: Test the GetAudioTrackInfo function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetAudioTrackInfoTest_001, TestSize.Level1) +{ + CLOGD("GetAudioTrackInfoTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + std::vector audioTrack; + auto result = streamPlayer->GetAudioTrackInfo(audioTrack); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetVideoWidthTest_001 + * @tc.desc: Test the GetVideoWidth function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetVideoWidthTest_001, TestSize.Level1) +{ + CLOGD("GetVideoWidthTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->GetVideoWidth(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetVideoHeightTest_001 + * @tc.desc: Test the GetVideoHeight function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetVideoHeightTest_001, TestSize.Level1) +{ + CLOGD("GetVideoHeightTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->GetVideoHeight(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetDurationTest_001 + * @tc.desc: Test the GetDuration function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetDurationTest_001, TestSize.Level1) +{ + CLOGD("GetDurationTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->GetDuration(); + EXPECT_EQ(result, CAST_STREAM_INT_INVALID); +} + +/** + * @tc.name: SetPlaybackSpeedTest_001 + * @tc.desc: Test the SetPlaybackSpeed function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetPlaybackSpeedTest_001, TestSize.Level1) +{ + CLOGD("SetPlaybackSpeedTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->SetPlaybackSpeed(Media::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: GetPlaybackSpeedTest_001 + * @tc.desc: Test the GetPlaybackSpeed function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, GetPlaybackSpeedTest_001, TestSize.Level1) +{ + CLOGD("GetPlaybackSpeedTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + Media::PlaybackRateMode mode; + auto result = streamPlayer->GetPlaybackSpeed(mode); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: SelectBitRateTest_001 + * @tc.desc: Test the SelectBitRate function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SelectBitRateTest_001, TestSize.Level1) +{ + CLOGD("SelectBitRateTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + uint32_t bitRate = 0; + auto result = streamPlayer->SelectBitRate(bitRate); + EXPECT_EQ(result, true); +} + +/** + * @tc.name: IsPlayingTest_001 + * @tc.desc: Test the IsPlaying function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, IsPlayingTest_001, TestSize.Level1) +{ + CLOGD("IsPlayingTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->IsPlaying(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: IsLoopingTest_001 + * @tc.desc: Test the IsLooping function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, IsLoopingTest_001, TestSize.Level1) +{ + CLOGD("IsLoopingTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->IsLooping(); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: SetParameterTest_001 + * @tc.desc: Test the IsLooping function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetParameterTest_001, TestSize.Level1) +{ + CLOGD("SetParameterTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + Media::Format param; + auto result = streamPlayer->SetParameter(param); + EXPECT_EQ(result, false); +} + +/** + * @tc.name: SetVideoSurfaceTest_001 + * @tc.desc: Test the IsLooping function. + * @tc.type: FUNC + */ +HWTEST_F(CastStreamPlayerTest, SetVideoSurfaceTest_001, TestSize.Level1) +{ + CLOGD("SetVideoSurfaceTest_001"); + auto streamPlayer = CreateStreamPlayer(); + ASSERT_NE(streamPlayer, nullptr); + auto result = streamPlayer->SetVideoSurface(nullptr); + EXPECT_EQ(result, false); +} +} +} +} diff --git a/test/unittest/phone/stream/remote_player_controller_test.cpp b/test/unittest/phone/stream/remote_player_controller_test.cpp new file mode 100644 index 0000000..d61ced3 --- /dev/null +++ b/test/unittest/phone/stream/remote_player_controller_test.cpp @@ -0,0 +1,871 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Connection Manager. + * Author: jiangfan + * Create: 2023-6-29 + */ + +#include "gtest/gtest.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "remote_player_controller.h" +#include "cast_stream_manager_client.h" +#include "i_cast_stream_listener.h" +#include "stream_player_listener_impl_stub.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; +using OHOS::CastEngine::CastEngineClient::StreamPlayerListenerImplStub; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineService { +DEFINE_CAST_ENGINE_LABEL("Remote-Player-Controller-Test"); + +class RemotePlayerControllerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastStreamListener : public ICastStreamListener { +public: + bool SendActionToPeers(int action, const std::string ¶m) override + { + return true; + } + void OnRenderReady(bool isReady) override {} + void OnEvent(EventId eventId, const std::string &data) override {} +}; + +namespace { +sptr g_listenerStub; + +void ReleaseCallback() +{ + CLOGD("Release Callback"); +} +} + +void RemotePlayerControllerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "remote_player_controller_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto result = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(result, Security::AccessToken::RET_SUCCESS); + g_listenerStub = new (std::nothrow) StreamPlayerListenerImplStub(nullptr); + ASSERT_NE(g_listenerStub, nullptr); +} + +void RemotePlayerControllerTest::TearDownTestCase(void) {} +void RemotePlayerControllerTest::SetUp(void) {} +void RemotePlayerControllerTest::TearDown(void) {} + +/** + * @tc.name: RegisterListenerTest_001 + * @tc.desc: Test the RegisterListener function. The empty listener is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, RegisterListenerTest_001, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->RegisterListener(nullptr); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: RegisterListenerTest_002 + * @tc.desc: Test the RegisterListener function. non-empty construction. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, RegisterListenerTest_002, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(callback, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->RegisterListener(g_listenerStub); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: RegisterListenerTest_003 + * @tc.desc: Test the RegisterListener function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, RegisterListenerTest_003, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_003"); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(nullptr, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->RegisterListener(g_listenerStub); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: UnregisterListener_001 + * @tc.desc: Test the UnregisterListener function. empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, UnregisterListener_001, TestSize.Level1) +{ + CLOGD("UnregisterListener_001"); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(nullptr, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: UnregisterListener_002 + * @tc.desc: Test the RegisterListener function. non-empty construction. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, UnregisterListener_002, TestSize.Level1) +{ + CLOGD("UnregisterListener_002"); + auto callback = std::make_shared(std::make_shared()); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(callback, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SetSurface_001 + * @tc.desc: Test the SetSurface function. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetSurface_001, TestSize.Level1) +{ + CLOGD("SetSurface_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->SetSurface(nullptr); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: LoadTest_001 + * @tc.desc: Test the Load function. empty callback and fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, LoadTest_001, TestSize.Level1) +{ + CLOGD("LoadTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"LoadTest_001", "LoadTest_001"}; + auto result = remoteController->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: LoadTest_002 + * @tc.desc: Test the Load function. non-empty callback and fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, LoadTest_002, TestSize.Level1) +{ + CLOGD("LoadTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(callback, fileChannel); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"LoadTest_002", "LoadTest_002"}; + auto result = remoteController->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: PlayTest_001 + * @tc.desc: Test the Play function. empty fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_001, TestSize.Level1) +{ + CLOGD("PlayTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"PlayTest_001", "PlayTest_001"}; + auto result = remoteController->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PlayTest_002 + * @tc.desc: Test the Play function. empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_002, TestSize.Level1) +{ + CLOGD("PlayTest_002"); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(nullptr, fileChannel); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"PlayTest_002", "PlayTest_002"}; + auto result = remoteController->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PlayTest_003 + * @tc.desc: Test the Play function. not empty callback and fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_003, TestSize.Level1) +{ + CLOGD("PlayTest_003"); + auto callback = std::make_shared(std::make_shared()); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(callback, fileChannel); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"PlayTest_003", "PlayTest_003"}; + auto result = remoteController->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: PlayTest_004 + * @tc.desc: Test the Play function. empty fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_004, TestSize.Level1) +{ + CLOGD("PlayTest_004"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + MediaInfo mediaInfo{"PlayTest_003", "PlayTest_003"}; + auto result = remoteController->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PlayTest_005 + * @tc.desc: Test the Play function. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_005, TestSize.Level1) +{ + CLOGD("PlayTest_005"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int index = 0; // non-boundary value + auto result = remoteController->Play(index); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PlayTest_006 + * @tc.desc: Test the Play function. empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_006, TestSize.Level1) +{ + CLOGD("PlayTest_006"); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(nullptr, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Play(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PlayTest_007 + * @tc.desc: Test the Play function. not empty callback and fileChannel. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PlayTest_007, TestSize.Level1) +{ + CLOGD("PlayTest_007"); + auto callback = std::make_shared(std::make_shared()); + auto fileChannel = std::make_shared(); + auto remoteController = std::make_shared(callback, fileChannel); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Play(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: PauseTest_001 + * @tc.desc: Test the Pause function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PauseTest_001, TestSize.Level1) +{ + CLOGD("PauseTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Pause(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PauseTest_002 + * @tc.desc: Test the Pause function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PauseTest_002, TestSize.Level1) +{ + CLOGD("PauseTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Pause(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: StopTest_001 + * @tc.desc: Test the Stop function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, StopTest_001, TestSize.Level1) +{ + CLOGD("StopTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Stop(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: StopTest_002 + * @tc.desc: Test the Stop function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, StopTest_002, TestSize.Level1) +{ + CLOGD("StopTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Stop(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: NextTest_001 + * @tc.desc: Test the Next function. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, NextTest_001, TestSize.Level1) +{ + CLOGD("NextTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Next(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: PreviousTest_001 + * @tc.desc: Test the Previous function. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, PreviousTest_001, TestSize.Level1) +{ + CLOGD("PreviousTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Previous(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SeekTest_001 + * @tc.desc: Test the Seek function.empty callback.Abnormal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SeekTest_001, TestSize.Level1) +{ + CLOGD("SeekTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int position = -1; // Abnormal data + auto result = remoteController->Seek(position); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: SeekTest_002 + * @tc.desc: Test the Seek function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SeekTest_002, TestSize.Level1) +{ + CLOGD("SeekTest_002"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int position = 0; // normal data + auto result = remoteController->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SeekTest_003 + * @tc.desc: Test the Seek function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SeekTest_003, TestSize.Level1) +{ + CLOGD("SeekTest_003"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int position = 0; // normal data + auto result = remoteController->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: FastForwardTest_001 + * @tc.desc: Test the FastForward function.empty callback.Abnormal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, FastForwardTest_001, TestSize.Level1) +{ + CLOGD("FastForwardTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int delta = -1; // Abnormal data + auto result = remoteController->FastForward(delta); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: FastForwardTest_002 + * @tc.desc: Test the FastForward function.empty callback.Normal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, FastForwardTest_002, TestSize.Level1) +{ + CLOGD("FastForwardTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int delta = 1000; // normal data + auto result = remoteController->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: FastRewindTest_001 + * @tc.desc: Test the FastRewind function.empty callback.Abnormal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, FastRewindTest_001, TestSize.Level1) +{ + CLOGD("FastRewindTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int delta = -1; // Abnormal data + auto result = remoteController->FastRewind(delta); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: FastRewindTest_002 + * @tc.desc: Test the FastRewind function.empty callback.Normal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, FastRewindTest_002, TestSize.Level1) +{ + CLOGD("FastRewindTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int delta = 1000; // normal data + auto result = remoteController->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SetVolumeTest_001 + * @tc.desc: Test the SetVolume function.Abnormal data. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetVolumeTest_001, TestSize.Level1) +{ + CLOGD("SetVolumeTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume = -1; // Abnormal data + auto result = remoteController->SetVolume(volume); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: SetVolumeTest_002 + * @tc.desc: Test the SetVolume function.Out of boundary value. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetVolumeTest_002, TestSize.Level1) +{ + CLOGD("SetVolumeTest_002"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume = 101; // Out of boundary value + auto result = remoteController->SetVolume(volume); + EXPECT_EQ(result, ERR_INVALID_PARAM); +} + +/** + * @tc.name: SetVolumeTest_003 + * @tc.desc: Test the SetVolume function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetVolumeTest_003, TestSize.Level1) +{ + CLOGD("SetVolumeTest_003"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume = 0; // normal data + auto result = remoteController->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SetVolumeTest_004 + * @tc.desc: Test the SetVolume function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetVolumeTest_004, TestSize.Level1) +{ + CLOGD("SetVolumeTest_004"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume = 0; // normal data + auto result = remoteController->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SetLoopModeTest_001 + * @tc.desc: Test the SetLoopMode function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("SetLoopModeTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->SetLoopMode(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SetLoopModeTest_002 + * @tc.desc: Test the SetLoopMode function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetLoopModeTest_002, TestSize.Level1) +{ + CLOGD("SetLoopModeTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->SetLoopMode(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: SetSpeedTest_001 + * @tc.desc: Test the SetSpeed function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetSpeedTest_001, TestSize.Level1) +{ + CLOGD("SetSpeedTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->SetSpeed(PlaybackSpeed::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: SetSpeedTest_002 + * @tc.desc: Test the SetSpeed function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, SetSpeedTest_002, TestSize.Level1) +{ + CLOGD("SetSpeedTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->SetSpeed(PlaybackSpeed::SPEED_FORWARD_0_75_X); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetPlayerStatusTest_001 + * @tc.desc: Test the GetPlayerStatus function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPlayerStatusTest_001, TestSize.Level1) +{ + CLOGD("GetPlayerStatusTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + PlayerStates playerStates; + auto result = remoteController->GetPlayerStatus(playerStates); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetPlayerStatusTest_002 + * @tc.desc: Test the GetPlayerStatus function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPlayerStatusTest_002, TestSize.Level1) +{ + CLOGD("GetPlayerStatusTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + PlayerStates playerStates; + auto result = remoteController->GetPlayerStatus(playerStates); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetPositionTest_001 + * @tc.desc: Test the GetPosition function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPositionTest_001, TestSize.Level1) +{ + CLOGD("GetPositionTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int position; + auto result = remoteController->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetPositionTest_002 + * @tc.desc: Test the GetPosition function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPositionTest_002, TestSize.Level1) +{ + CLOGD("GetPositionTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int position; + auto result = remoteController->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetDurationTest_001 + * @tc.desc: Test the GetDuration function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetDurationTest_001, TestSize.Level1) +{ + CLOGD("GetDurationTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int position; + auto result = remoteController->GetDuration(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetDurationTest_002 + * @tc.desc: Test the GetDuration function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetDurationTest_002, TestSize.Level1) +{ + CLOGD("GetDurationTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int duration; + auto result = remoteController->GetDuration(duration); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetVolumeTest_001 + * @tc.desc: Test the GetVolume function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetVolumeTest_001, TestSize.Level1) +{ + CLOGD("GetVolumeTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume; + int maxVolume; + auto result = remoteController->GetVolume(volume, maxVolume); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetVolumeTest_002 + * @tc.desc: Test the GetVolume function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetVolumeTest_002, TestSize.Level1) +{ + CLOGD("GetVolumeTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + int volume; + int maxVolume; + auto result = remoteController->GetVolume(volume, maxVolume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetLoopModeTest_001 + * @tc.desc: Test the GetLoopMode function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("GetLoopModeTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + LoopMode loopMode; + auto result = remoteController->GetLoopMode(loopMode); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetLoopModeTest_002 + * @tc.desc: Test the GetLoopMode function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetLoopModeTest_002, TestSize.Level1) +{ + CLOGD("GetLoopModeTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + LoopMode loopMode; + auto result = remoteController->GetLoopMode(loopMode); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetPlaySpeedTest_001 + * @tc.desc: Test the GetPlaySpeed function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPlaySpeedTest_001, TestSize.Level1) +{ + CLOGD("GetPlaySpeedTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + PlaybackSpeed playbackSpeed; + auto result = remoteController->GetPlaySpeed(playbackSpeed); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: GetPlaySpeedTest_002 + * @tc.desc: Test the GetPlaySpeed function.non empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetPlaySpeedTest_002, TestSize.Level1) +{ + CLOGD("GetPlaySpeedTest_002"); + auto callback = std::make_shared(std::make_shared()); + auto remoteController = std::make_shared(callback, nullptr); + ASSERT_NE(remoteController, nullptr); + PlaybackSpeed playbackSpeed; + auto result = remoteController->GetPlaySpeed(playbackSpeed); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} + +/** + * @tc.name: GetMediaInfoHolderTest_001 + * @tc.desc: Test the GetMediaInfoHolder function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, GetMediaInfoHolderTest_001, TestSize.Level1) +{ + CLOGD("GetMediaInfoHolderTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + MediaInfoHolder mediaInfoHolder; + auto result = remoteController->GetMediaInfoHolder(mediaInfoHolder); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: ReleaseTest_001 + * @tc.desc: Test the Release function.empty callback. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, ReleaseTest_001, TestSize.Level1) +{ + CLOGD("ReleaseTest_001"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + auto result = remoteController->Release(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); +} + +/** + * @tc.name: ReleaseTest_002 + * @tc.desc: Test the Release function.Setting Callback in Advance. + * @tc.type: FUNC + */ +HWTEST_F(RemotePlayerControllerTest, ReleaseTest_002, TestSize.Level1) +{ + CLOGD("ReleaseTest_002"); + auto remoteController = std::make_shared(nullptr, nullptr); + ASSERT_NE(remoteController, nullptr); + remoteController->SetSessionCallbackForRelease(ReleaseCallback); + auto result = remoteController->Release(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); +} +} +} +} \ No newline at end of file diff --git a/test/unittest/phone/stream/stream_player_listener_impl_stub_test.cpp b/test/unittest/phone/stream/stream_player_listener_impl_stub_test.cpp new file mode 100644 index 0000000..57658df --- /dev/null +++ b/test/unittest/phone/stream/stream_player_listener_impl_stub_test.cpp @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Connection Manager. + * Author: jiangfan + * Create: 2023-7-3 + */ + +#include "gtest/gtest.h" +#include "cast_engine_common.h" +#include "cast_engine_common_helper.h" +#include "cast_engine_errors.h" +#include "cast_engine_log.h" +#include "stream_player_listener_impl_stub.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" +#include "ipc_types.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Stream-Player-Listener-Impl_Stub-Test"); + +class StreamPlayerListenerImplStubTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestStreamPlayerListener : public IStreamPlayerListener { +public: + void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) override {} + void OnPositionChanged(int position, int bufferPosition, int duration) override {} + void OnMediaItemChanged(const MediaInfo &mediaInfo) override {} + void OnVolumeChanged(int volume, int maxVolume) override {} + void OnLoopModeChanged(const LoopMode loopMode) override {} + void OnPlaySpeedChanged(const PlaybackSpeed speed) override {} + void OnPlayerError(int errorCode, const std::string &errorMsg) override {} + void OnVideoSizeChanged(int width, int height) override {} + void OnNextRequest() override {} + void OnPreviousRequest() override {} + void OnSeekDone(int position) override {} + void OnEndOfStream(int isLooping) override {} + void OnPlayRequest(const MediaInfo &mediaInfo) override {} +}; + +namespace { +std::shared_ptr CreatelistenerStub() +{ + auto userListener_ = std::make_shared(); + if (!userListener_) { + return nullptr; + } + return std::make_shared(userListener_); +} + +enum { + ON_PLAYER_STATUS_CHANGED = 1, + ON_POSITION_CHANGED, + ON_MEDIA_ITEM_CHANGED, + ON_VOLUME_CHANGED, + ON_REPEAT_MODE_CHANGED, + ON_PLAY_SPEED_CHANGED, + ON_PLAYER_ERROR, + ON_VIDEO_SIZE_CHANGED, + ON_NEXT_REQUEST, + ON_PREVIOUS_REQUEST, + ON_SEEK_DONE, + ON_END_OF_STREAM, + ON_PLAY_REQUEST, + INVALID_CODE +}; +} + +void StreamPlayerListenerImplStubTest::SetUpTestCase(void) {} +void StreamPlayerListenerImplStubTest::TearDownTestCase(void) {} +void StreamPlayerListenerImplStubTest::SetUp(void) {} +void StreamPlayerListenerImplStubTest::TearDown(void) {} + +/** + * @tc.name: OnRemoteRequestTest_001 + * @tc.desc: Test the OnRemoteRequest function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, OnRemoteRequestTest_001, TestSize.Level1) +{ + CLOGD("OnRemoteRequestTest_001"); + auto listenerImplStub = std::make_shared(nullptr); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAYER_STATUS_CHANGED, data, reply, option); + EXPECT_EQ(result, ERR_NULL_OBJECT); +} + +/** + * @tc.name: OnRemoteRequestTest_002 + * @tc.desc: Test the OnRemoteRequest function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, OnRemoteRequestTest_002, TestSize.Level1) +{ + CLOGD("OnRemoteRequestTest_002"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAYER_STATUS_CHANGED, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: OnRemoteRequestTest_003 + * @tc.desc: Test the OnRemoteRequest function.error code. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, OnRemoteRequestTest_003, TestSize.Level1) +{ + CLOGD("OnRemoteRequestTest_003"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(INVALID_CODE, data, reply, option); + EXPECT_EQ(result, IPC_STUB_UNKNOW_TRANS_ERR); +} + +/** + * @tc.name: DoOnLoopModeChangedTaskTest_001 + * @tc.desc: Test the DoOnLoopModeChangedTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnLoopModeChangedTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnLoopModeChangedTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_REPEAT_MODE_CHANGED, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnPlaySpeedChangedTaskTest_001 + * @tc.desc: Test the DoOnPlaySpeedChangedTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnPlaySpeedChangedTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnPlaySpeedChangedTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAY_SPEED_CHANGED, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnPlayerErrorTaskTest_001 + * @tc.desc: Test the DoOnPlayerErrorTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnPlayerErrorTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnPlayerErrorTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAYER_ERROR, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnVideoSizeChangedTaskTest_001 + * @tc.desc: Test the DoOnVideoSizeChangedTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnVideoSizeChangedTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnVideoSizeChangedTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_VIDEO_SIZE_CHANGED, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnNextRequestTaskTest_001 + * @tc.desc: Test the DoOnNextRequestTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnNextRequestTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnNextRequestTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_NEXT_REQUEST, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnPreviousRequestTaskTest_001 + * @tc.desc: Test the DoOnPreviousRequestTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnPreviousRequestTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnPreviousRequestTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PREVIOUS_REQUEST, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnSeekDoneTaskTest_001 + * @tc.desc: Test the DoOnSeekDoneTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnSeekDoneTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnSeekDoneTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_SEEK_DONE, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnEndOfStreamTaskTest_001 + * @tc.desc: Test the DoOnEndOfStreamTask function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnEndOfStreamTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnEndOfStreamTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_END_OF_STREAM, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnPlayRequestTaskTest_001 + * @tc.desc: Test the DoOnPlayRequestTaskTest function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnPlayRequestTaskTest_001, TestSize.Level1) +{ + CLOGD("DoOnPlayRequestTaskTest_001"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAY_REQUEST, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} + +/** + * @tc.name: DoOnPlayRequestTaskTest_002 + * @tc.desc: Test the DoOnPlayRequestTaskTest function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerListenerImplStubTest, DoOnPlayRequestTaskTest_002, TestSize.Level1) +{ + CLOGD("DoOnPlayRequestTaskTest_002"); + auto listenerImplStub = CreatelistenerStub(); + ASSERT_NE(listenerImplStub, nullptr); + MessageParcel data; + MessageParcel reply; + MessageOption option; + data.WriteInterfaceToken(StreamPlayerListenerImplStub::GetDescriptor()); + MediaInfo mediaInfo = MediaInfo{}; + WriteMediaInfo(data, mediaInfo); + auto result = listenerImplStub->OnRemoteRequest(ON_PLAY_REQUEST, data, reply, option); + EXPECT_EQ(result, ERR_NONE); +} +} +} +} \ No newline at end of file diff --git a/test/unittest/phone/stream/stream_player_test.cpp b/test/unittest/phone/stream/stream_player_test.cpp new file mode 100644 index 0000000..519e853 --- /dev/null +++ b/test/unittest/phone/stream/stream_player_test.cpp @@ -0,0 +1,1219 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Description: Test Cast Session. + * Author: jiangfan + * Create: 2023-6-8 + */ + +#include +#include +#include +#include "gtest/gtest.h" +#include "cast_engine_log.h" +#include "cast_engine_common.h" +#include "cast_engine_errors.h" +#include "cast_session_manager.h" +#include "stream_player.h" +#include "accesstoken_kit.h" +#include "nativetoken_kit.h" +#include "token_setproc.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS { +namespace CastEngine { +namespace CastEngineClient { +DEFINE_CAST_ENGINE_LABEL("Stream-Player-Test"); + +class StreamPlayerTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + + void SetUp() override; + void TearDown() override; +}; + +class TestCastSessionManagerListener : public ICastSessionManagerListener { +public: + void OnDeviceFound(const std::vector &deviceList) override + { + static_cast(deviceList); + } + void OnSessionCreated(const std::shared_ptr &castSession) override + { + static_cast(castSession); + } + void OnServiceDied() override {} + void OnDeviceOffline(const std::string &deviceId) override + { + static_cast(deviceId); + } +}; + +class TestCastSessionListener : public ICastSessionListener { +public: + void OnDeviceState(const DeviceStateInfo &stateInfo) override + { + static_cast(stateInfo); + } + void OnEvent(const EventId &eventId, const std::string &jsonParam) override + { + static_cast(eventId); + static_cast(jsonParam); + } +}; + +class BufferConsumerListener : public ::OHOS::IBufferConsumerListener { +public: + void OnBufferAvailable() override {} +}; + +class TestStreamPlayerListener : public IStreamPlayerListener { +public: + void OnStateChanged(const PlayerStates playbackState, bool isPlayWhenReady) override {} + void OnPositionChanged(int position, int bufferPosition, int duration) override {} + void OnMediaItemChanged(const MediaInfo &mediaInfo) override {} + void OnVolumeChanged(int volume, int maxVolume) override {} + void OnLoopModeChanged(const LoopMode loopMode) override {} + void OnPlaySpeedChanged(const PlaybackSpeed speed) override {} + void OnPlayerError(int errorCode, const std::string &errorMsg) override {} + void OnVideoSizeChanged(int width, int height) override {} + void OnNextRequest() override {} + void OnPreviousRequest() override {} + void OnSeekDone(int position) override {} + void OnEndOfStream(int isLooping) override {} + void OnPlayRequest(const MediaInfo &mediaInfo) override {} +}; + +namespace { +std::shared_ptr g_session; + +std::shared_ptr CreateStream() +{ + std::shared_ptr stream; + auto result = g_session->RegisterListener(std::make_shared()); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + g_session->CreateStreamPlayer(stream); + EXPECT_NE(stream, nullptr); + return stream; +} + +std::string CreateSurfaceId() +{ + sptr consSurface; + sptr producer; + sptr prodSurface; + consSurface = IConsumerSurface::Create(); + if (!consSurface) { + return ""; + } + sptr surfaceListener = new BufferConsumerListener(); + if (!surfaceListener) { + return ""; + } + auto result = consSurface->RegisterConsumerListener(surfaceListener); + EXPECT_EQ(result, OHOS::GSError::GSERROR_OK); + producer = consSurface->GetProducer(); + if (!producer) { + return ""; + } + prodSurface = Surface::CreateSurfaceAsProducer(producer); + if (!prodSurface) { + return ""; + } + SurfaceUtils::GetInstance()->Add(prodSurface->GetUniqueId(), prodSurface); + auto uniqueId = prodSurface->GetUniqueId(); + std::string surfaceId = std::to_string(uniqueId); + return surfaceId; +} +} + +void StreamPlayerTest::SetUpTestCase(void) +{ + constexpr int castPermissionNum = 2; + const char *perms[castPermissionNum] = { + "ohos.permission.ACCESS_CAST_ENGINE_MIRROR", + "ohos.permission.ACCESS_CAST_ENGINE_STREAM", + }; + NativeTokenInfoParams infoInstance = { + .dcapsNum = 0, // Indicates the capsbility list of the sa. + .permsNum = castPermissionNum, + .aclsNum = 0, // acls is the list of rights that can be escalated. + .dcaps = nullptr, + .perms = perms, + .acls = nullptr, + .processName = "stream_player_test", + .aplStr = "system_basic", + }; + uint64_t tokenId = GetAccessTokenId(&infoInstance); + CLOGI("tokenId is %" PRIu64, tokenId); + SetSelfTokenID(tokenId); + auto ret = Security::AccessToken::AccessTokenKit::ReloadNativeTokenInfo(); + EXPECT_EQ(ret, Security::AccessToken::RET_SUCCESS); + auto listener = std::make_shared(); + auto result = CastSessionManager::GetInstance().RegisterListener(listener); + ASSERT_EQ(result, CAST_ENGINE_SUCCESS); + CastSessionManager::GetInstance().CreateCastSession(CastSessionProperty{}, g_session); + ASSERT_NE(g_session, nullptr); +} + +void StreamPlayerTest::TearDownTestCase(void) +{ + CastSessionManager::GetInstance().UnregisterListener(); + CastSessionManager::GetInstance().Release(); +} + +void StreamPlayerTest::SetUp(void) {} +void StreamPlayerTest::TearDown(void) {} + +/** + * @tc.name: RegisterListenerTest_001 + * @tc.desc: Test the RegisterListener function. The empty listener is input, false is returned. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, RegisterListenerTest_001, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->RegisterListener(nullptr); + EXPECT_EQ(result, ERR_INVALID_PARAM); + stream->Release(); +} + +/** + * @tc.name: RegisterListenerTest_002 + * @tc.desc: Test the RegisterListener function.Transfer non-null listener deregistration. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, RegisterListenerTest_002, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->RegisterListener(std::make_shared()); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: RegisterListenerTest_003 + * @tc.desc: Test the RegisterListener function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, RegisterListenerTest_003, TestSize.Level1) +{ + CLOGD("RegisterListenerTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->RegisterListener(std::make_shared()); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: UnregisterListenerTest_001 + * @tc.desc: Test the UnregisterListener function.Unregistered interception. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, UnregisterListenerTest_001, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: UnregisterListenerTest_002 + * @tc.desc: Test the UnregisterListener function.Listening initialized. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, UnregisterListenerTest_002, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: UnregisterListenerTest_003 + * @tc.desc: Test the UnregisterListener function.Proxy is null + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, UnregisterListenerTest_003, TestSize.Level1) +{ + CLOGD("UnregisterListenerTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->UnregisterListener(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetSurfaceTest_001 + * @tc.desc: Test the SetSurface function.The input surface ID is empty. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSurfaceTest_001, TestSize.Level1) +{ + CLOGD("SetSurfaceTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->SetSurface(""); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetSurfaceTest_002 + * @tc.desc: Test the SetSurface function.Registering a Listener..Construction surface ID. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSurfaceTest_002, TestSize.Level1) +{ + CLOGD("SetSurfaceTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->SetSurface(CreateSurfaceId()); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: SetSurfaceTest_003 + * @tc.desc: Test the SetSurface function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSurfaceTest_003, TestSize.Level1) +{ + CLOGD("SetSurfaceTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->SetSurface(CreateSurfaceId()); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: LoadTest_001 + * @tc.desc: Test the Load function.The input mediaUrl is empty. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, LoadTest_001, TestSize.Level1) +{ + CLOGD("LoadTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"LoadTest_001", "LoadTest_001"}; + auto result = stream->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: LoadTest_002 + * @tc.desc: Test the Load function.The input mediaUrl is not empty. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, LoadTest_002, TestSize.Level1) +{ + CLOGD("LoadTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"LoadTest_002", "LoadTest_002", "LoadTest_002"}; + auto result = stream->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: LoadTest_003 + * @tc.desc: Test the Load function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, LoadTest_003, TestSize.Level1) +{ + CLOGD("LoadTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"LoadTest_003", "LoadTest_003", "LoadTest_003"}; + auto result = stream->Load(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PlayTest_001 + * @tc.desc: Test the Play function.The input mediaUrl is empty. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_001, TestSize.Level1) +{ + CLOGD("PlayTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"PlayTest_001", "PlayTest_001"}; + auto result = stream->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PlayTest_002 + * @tc.desc: Test the Play function.The input mediaUrl is not empty. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_002, TestSize.Level1) +{ + CLOGD("PlayTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"PlayTest_002", "PlayTest_002", "http://PlayTest_002"}; + auto result = stream->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: PlayTest_003 + * @tc.desc: Test the Play function.The input non-boundary value. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_003, TestSize.Level1) +{ + CLOGD("PlayTest_003"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + int index = 0; // non-boundary value + auto result = stream->Play(index); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: PlayTest_004 + * @tc.desc: Test the Play function.Not in playable state. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_004, TestSize.Level1) +{ + CLOGD("PlayTest_004"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->Play(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PlayTest_005 + * @tc.desc: Test the Play function.Prerequisite: Playable. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_005, TestSize.Level1) +{ + CLOGD("PlayTest_005"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"PlayTest_005", "PlayTest_005", "http://PlayTest_005"}; + stream->Play(mediaInfo); + stream->Pause(); + auto result = stream->Play(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: PlayTest_007 + * @tc.desc: Test the Play function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_007, TestSize.Level1) +{ + CLOGD("PlayTest_007"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + MediaInfo mediaInfo{"PlayTest_007", "PlayTest_007", "http://PlayTest_007"}; + auto result = stream->Play(mediaInfo); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PlayTest_008 + * @tc.desc: Test the Play function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_008, TestSize.Level1) +{ + CLOGD("PlayTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int index = 0; // non-boundary value + auto result = stream->Play(index); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PlayTest_009 + * @tc.desc: Test the Play function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PlayTest_009, TestSize.Level1) +{ + CLOGD("PlayTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Play(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PauseTest_001 + * @tc.desc: Test the Pause function.Cannot pause when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PauseTest_001, TestSize.Level1) +{ + CLOGD("PauseTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->Pause(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PauseTest_002 + * @tc.desc: Test the Pause function.When playing, can pause it. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PauseTest_002, TestSize.Level1) +{ + CLOGD("PauseTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"PauseTest_002", "PauseTest_002", "http://PauseTest_002"}; + stream->Play(mediaInfo); + auto result = stream->Pause(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: PauseTest_003 + * @tc.desc: Test the Pause function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PauseTest_003, TestSize.Level1) +{ + CLOGD("PauseTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Pause(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: StopTest_001 + * @tc.desc: Test the Stop function.Cannot stop when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, StopTest_001, TestSize.Level1) +{ + CLOGD("StopTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->Stop(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: StopTest_002 + * @tc.desc: Test the Stop function.When playing, can stop it. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, StopTest_002, TestSize.Level1) +{ + CLOGD("StopTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"StopTest_002", "StopTest_002", "http://StopTest_002"}; + stream->Play(mediaInfo); + auto result = stream->Stop(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: StopTest_003 + * @tc.desc: Test the Stop function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, StopTest_003, TestSize.Level1) +{ + CLOGD("StopTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Stop(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: NextTest_001 + * @tc.desc: Test the Next function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, NextTest_001, TestSize.Level1) +{ + CLOGD("NextTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->Next(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: NextTest_002 + * @tc.desc: Test the Stop function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, NextTest_002, TestSize.Level1) +{ + CLOGD("NextTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Next(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: PreviousTest_001 + * @tc.desc: Test the Previous function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PreviousTest_001, TestSize.Level1) +{ + CLOGD("PreviousTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + auto result = stream->Previous(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: PreviousTest_002 + * @tc.desc: Test the Previous function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, PreviousTest_002, TestSize.Level1) +{ + CLOGD("PreviousTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Previous(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SeekTest_001 + * @tc.desc: Test the Seek function.Cannot seek position when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SeekTest_001, TestSize.Level1) +{ + CLOGD("SeekTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + int position = 0; // start position + auto result = stream->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SeekTest_002 + * @tc.desc: Test the Seek function.When playing, can seek position. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SeekTest_002, TestSize.Level1) +{ + CLOGD("SeekTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"SeekTest_002", "SeekTest_002", "http://SeekTest_002"}; + stream->Play(mediaInfo); + int position = 0; // start position + auto result = stream->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: SeekTest_003 + * @tc.desc: Test the Seek function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SeekTest_003, TestSize.Level1) +{ + CLOGD("SeekTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int position = 0; // start position + auto result = stream->Seek(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: FastForwardTest_001 + * @tc.desc: Test the FastForward function.Cannot FastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastForwardTest_001, TestSize.Level1) +{ + CLOGD("FastForwardTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"FastForwardTest_001", "FastForwardTest_001", "http://FastForwardTest_001"}; + stream->Play(mediaInfo); + int delta = 1000; + auto result = stream->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: FastForwardTest_002 + * @tc.desc: Test the FastForward function.Cannot FastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastForwardTest_002, TestSize.Level1) +{ + CLOGD("FastForwardTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + int delta = 1000; + auto result = stream->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: FastForwardTest_003 + * @tc.desc: Test the FastForward function.Cannot FastForward when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastForwardTest_003, TestSize.Level1) +{ + CLOGD("FastForwardTest_003"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"FastForwardTest_003", "FastForwardTest_003", "http://FastForwardTest_003"}; + stream->Play(mediaInfo); + int delta = -1000; + auto result = stream->FastForward(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: FastRewindTest_001 + * @tc.desc: Test the FastRewind function.Cannot FastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastRewindTest_001, TestSize.Level1) +{ + CLOGD("FastRewindTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"FastRewindTest_001", "FastRewindTest_001", "http://FastRewindTest_001"}; + stream->Play(mediaInfo); + int delta = 1000; + auto result = stream->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: FastRewindTest_002 + * @tc.desc: Test the FastRewind function.Cannot FastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastRewindTest_002, TestSize.Level1) +{ + CLOGD("FastRewindTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + int delta = 1000; + auto result = stream->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: FastRewindTest_003 + * @tc.desc: Test the FastRewind function.Cannot FastRewind when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, FastRewindTest_003, TestSize.Level1) +{ + CLOGD("FastRewindTest_003"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"FastRewindTest_003", "FastRewindTest_003", "http://FastRewindTest_003"}; + stream->Play(mediaInfo); + int delta = -1000; + auto result = stream->FastRewind(delta); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetVolumeTest_001 + * @tc.desc: Test the SetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetVolumeTest_001, TestSize.Level1) +{ + CLOGD("SetVolumeTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->RegisterListener(std::make_shared()); + int32_t volume = 0; + auto result = stream->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: SetVolumeTest_002 + * @tc.desc: Test the SetVolume function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetVolumeTest_002, TestSize.Level1) +{ + CLOGD("SetVolumeTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int32_t volume = 0; + auto result = stream->SetVolume(volume); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetLoopModeTest_001 + * @tc.desc: Test the SetLoopMode function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("SetLoopModeTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->SetLoopMode(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: SetLoopModeTest_002 + * @tc.desc: Test the SetLoopMode function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetLoopModeTest_002, TestSize.Level1) +{ + CLOGD("SetLoopModeTest_001"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->SetLoopMode(LoopMode::LOOP_MODE_SEQUENCE); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetSpeedTest_001 + * @tc.desc: Test the SetSpeed function.Cannot set speed when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSpeedTest_001, TestSize.Level1) +{ + CLOGD("SetSpeedTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->SetSpeed(PlaybackSpeed::SPEED_FORWARD_1_00_X); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: SetSpeedTest_002 + * @tc.desc: Test the SetSpeed function.When playing, can set speed position. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSpeedTest_002, TestSize.Level1) +{ + CLOGD("SetSpeedTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"SetSpeedTest_002", "SetSpeedTest_002", "http://SetSpeedTest_002"}; + stream->Play(mediaInfo); + auto result = stream->SetSpeed(PlaybackSpeed::SPEED_FORWARD_1_00_X); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: SetSpeedTest_003 + * @tc.desc: Test the SetSpeed function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, SetSpeedTest_003, TestSize.Level1) +{ + CLOGD("SetSpeedTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->SetSpeed(PlaybackSpeed::SPEED_FORWARD_1_00_X); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetPlayerStatusTest_001 + * @tc.desc: Test the GetPlayerStatus function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPlayerStatusTest_001, TestSize.Level1) +{ + CLOGD("GetPlayerStatusTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + PlayerStates playerStates; + auto result = stream->GetPlayerStatus(playerStates); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetPlayerStatusTest_002 + * @tc.desc: Test the GetPlayerStatus function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPlayerStatusTest_002, TestSize.Level1) +{ + CLOGD("GetPlayerStatusTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + PlayerStates playerStates; + auto result = stream->GetPlayerStatus(playerStates); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetPositionTest_001 + * @tc.desc: Test the GetPosition function.Cannot get position when not playing. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPositionTest_001, TestSize.Level1) +{ + CLOGD("GetPositionTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + int position; + auto result = stream->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetPositionTest_002 + * @tc.desc: Test the GetPosition function.When playing, can get position. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPositionTest_002, TestSize.Level1) +{ + CLOGD("GetPositionTest_002"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + stream->SetSurface(CreateSurfaceId()); + MediaInfo mediaInfo{"GetPositionTest_002", "GetPositionTest_002", "http://GetPositionTest_002"}; + stream->Play(mediaInfo); + int position; + auto result = stream->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetPositionTest_003 + * @tc.desc: Test the GetPosition function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPositionTest_003, TestSize.Level1) +{ + CLOGD("GetPositionTest_003"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int position; + auto result = stream->GetPosition(position); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetDurationTest_001 + * @tc.desc: Test the GetDuration function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetDurationTest_001, TestSize.Level1) +{ + CLOGD("GetDurationTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + int duration; + auto result = stream->GetDuration(duration); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetDurationTest_002 + * @tc.desc: Test the GetDuration function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetDurationTest_002, TestSize.Level1) +{ + CLOGD("GetDurationTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int duration; + auto result = stream->GetDuration(duration); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetVolumeTest_001 + * @tc.desc: Test the GetVolume function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetVolumeTest_001, TestSize.Level1) +{ + CLOGD("GetVolumeTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + int volume; + int maxVolume; + auto result = stream->GetVolume(volume, maxVolume); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetVolumeTest_002 + * @tc.desc: Test the GetVolume function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetVolumeTest_002, TestSize.Level1) +{ + CLOGD("GetVolumeTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + int volume; + int maxVolume; + auto result = stream->GetVolume(volume, maxVolume); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetLoopModeTest_001 + * @tc.desc: Test the GetLoopMode function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetLoopModeTest_001, TestSize.Level1) +{ + CLOGD("GetLoopModeTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + LoopMode sequence = LoopMode::LOOP_MODE_SEQUENCE; + auto result = stream->GetLoopMode(sequence); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetLoopModeTest_002 + * @tc.desc: Test the GetLoopMode function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetLoopModeTest_002, TestSize.Level1) +{ + CLOGD("GetLoopModeTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + LoopMode sequence = LoopMode::LOOP_MODE_SEQUENCE; + auto result = stream->GetLoopMode(sequence); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetPlaySpeedTest_001 + * @tc.desc: Test the GetPlaySpeed function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPlaySpeedTest_001, TestSize.Level1) +{ + CLOGD("GetPlaySpeedTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + PlaybackSpeed playBackSpeed = PlaybackSpeed::SPEED_FORWARD_0_75_X; + auto result = stream->GetPlaySpeed(playBackSpeed); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: GetPlaySpeedTest_002 + * @tc.desc: Test the GetPlaySpeed function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetPlaySpeedTest_002, TestSize.Level1) +{ + CLOGD("GetPlaySpeedTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + PlaybackSpeed playBackSpeed = PlaybackSpeed::SPEED_FORWARD_0_75_X; + auto result = stream->GetPlaySpeed(playBackSpeed); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetMediaInfoHolderTest_001 + * @tc.desc: Test the GetMediaInfoHolder function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetMediaInfoHolderTest_001, TestSize.Level1) +{ + CLOGD("GetMediaInfoHolderTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + MediaInfoHolder mediaInfoHolder; + auto result = stream->GetMediaInfoHolder(mediaInfoHolder); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: GetMediaInfoHolderTest_002 + * @tc.desc: Test the GetMediaInfoHolder function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, GetMediaInfoHolderTest_002, TestSize.Level1) +{ + CLOGD("GetMediaInfoHolderTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + PlaybackSpeed playBackSpeed = PlaybackSpeed::SPEED_FORWARD_0_75_X; + auto result = stream->GetPlaySpeed(playBackSpeed); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} + +/** + * @tc.name: ReleaseTest_001 + * @tc.desc: Test the Release function. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, ReleaseTest_001, TestSize.Level1) +{ + CLOGD("ReleaseTest_001"); + std::shared_ptr stream = CreateStream(); + ASSERT_NE(stream, nullptr); + auto result = stream->Release(); + EXPECT_EQ(result, CAST_ENGINE_SUCCESS); + stream->Release(); +} + +/** + * @tc.name: ReleaseTest_002 + * @tc.desc: Test the Release function.Proxy is null. + * @tc.type: FUNC + */ +HWTEST_F(StreamPlayerTest, ReleaseTest_002, TestSize.Level1) +{ + CLOGD("ReleaseTest_002"); + std::shared_ptr stream = std::make_shared(nullptr); + ASSERT_NE(stream, nullptr); + auto result = stream->Release(); + EXPECT_EQ(result, CAST_ENGINE_ERROR); + stream->Release(); +} +} +} +} \ No newline at end of file