From 8cc5bfae5f8a202863a5ea5009aefd7e29bedd1e Mon Sep 17 00:00:00 2001 From: lvqiang214 Date: Mon, 26 Jun 2023 21:42:44 +0800 Subject: [PATCH] merge intelligent_voice_framework format fix Signed-off-by: lvqiang214 --- LICENSE | 177 ++++ OAT.xml | 64 ++ README_zh.md | 195 +++++ bundle.json | 57 ++ figures/intelligent-voice-framework.png | Bin 0 -> 55004 bytes frameworks/js/BUILD.gn | 73 ++ .../js/napi/engine_event_callback_napi.cpp | 118 +++ .../js/napi/engine_event_callback_napi.h | 59 ++ ...roll_intell_voice_engine_callback_napi.cpp | 152 ++++ ...enroll_intell_voice_engine_callback_napi.h | 78 ++ .../napi/enroll_intell_voice_engine_napi.cpp | 504 +++++++++++ .../js/napi/enroll_intell_voice_engine_napi.h | 67 ++ .../js/napi/intell_voice_manager_napi.cpp | 420 +++++++++ .../js/napi/intell_voice_manager_napi.h | 62 ++ .../js/napi/intell_voice_napi_queue.cpp | 193 ++++ frameworks/js/napi/intell_voice_napi_queue.h | 81 ++ frameworks/js/napi/intell_voice_napi_util.cpp | 124 +++ frameworks/js/napi/intell_voice_napi_util.h | 51 ++ .../napi/wakeup_intell_voice_engine_napi.cpp | 444 ++++++++++ .../js/napi/wakeup_intell_voice_engine_napi.h | 62 ++ frameworks/native/BUILD.gn | 52 ++ .../native/enroll_intell_voice_engine.cpp | 163 ++++ frameworks/native/intell_voice_manager.cpp | 88 ++ .../native/wakeup_intell_voice_engine.cpp | 106 +++ .../native/enroll_intell_voice_engine.h | 62 ++ .../inner_api/native/intell_voice_info.h | 87 ++ .../inner_api/native/intell_voice_manager.h | 42 + .../native/wakeup_intell_voice_engine.h | 54 ++ .../kits/js/@ohos.ai.intelligentVoice.d.ts | 823 ++++++++++++++++++ llt/hdt/CMakeLists.txt | 64 ++ llt/hdt/build.sh | 24 + llt/hdt/depend_libs/cmake/CMakeLists.txt | 23 + llt/hdt/depend_libs/cmake/libhilog.cmake | 31 + llt/hdt/depend_libs/cmake/libsec.cmake | 27 + llt/hdt/depend_libs/cmake/libutilsbase.cmake | 24 + llt/hdt/depend_libs/src/file_ex.cpp | 346 ++++++++ llt/hdt/run.sh | 23 + llt/hdt/stub/message_parcel.cpp | 29 + .../intell_voice_utils/test_time_util.cpp | 40 + sa_profile/2688.xml | 25 + sa_profile/BUILD.gn | 19 + services/BUILD.gn | 146 ++++ services/etc/BUILD.gn | 21 + services/etc/intell_voice_service.cfg | 22 + services/etc/intell_voice_service.rc | 8 + .../i_intell_voice_engine.h | 66 ++ .../i_intell_voice_engine_callback.h | 44 + .../i_intell_voice_service.h | 37 + .../proxy/engine_callback_inner.cpp | 39 + .../proxy/engine_callback_inner.h | 33 + .../intell_voice_engine_callback_stub.cpp | 59 ++ .../proxy/intell_voice_engine_callback_stub.h | 32 + .../proxy/intell_voice_engine_proxy.cpp | 132 +++ .../proxy/intell_voice_engine_proxy.h | 43 + .../proxy/intell_voice_service_proxy.cpp | 56 ++ .../proxy/intell_voice_service_proxy.h | 39 + .../server/base/adapter_callback_service.cpp | 33 + .../server/base/adapter_callback_service.h | 37 + .../server/base/audio_source.cpp | 182 ++++ .../server/base/audio_source.h | 63 ++ .../server/base/engine_base.cpp | 90 ++ .../server/base/engine_base.h | 67 ++ .../server/base/engine_factory.cpp | 46 + .../server/base/engine_factory.h | 30 + .../server/base/file_source.cpp | 133 +++ .../server/base/file_source.h | 61 ++ .../base/intell_voice_adapter_listener.h | 30 + .../server/enroll/enroll_adapter_listener.cpp | 48 + .../server/enroll/enroll_adapter_listener.h | 40 + .../server/enroll/enroll_engine.cpp | 377 ++++++++ .../server/enroll/enroll_engine.h | 60 ++ .../sa/intell_voice_engine_callback_proxy.cpp | 60 ++ .../sa/intell_voice_engine_callback_proxy.h | 36 + .../server/sa/intell_voice_engine_stub.cpp | 77 ++ .../server/sa/intell_voice_engine_stub.h | 35 + .../server/sa/intell_voice_service.cpp | 205 +++++ .../server/sa/intell_voice_service.h | 62 ++ .../sa/intell_voice_service_manager.cpp | 368 ++++++++ .../server/sa/intell_voice_service_manager.h | 87 ++ .../server/sa/intell_voice_service_stub.cpp | 48 + .../server/sa/intell_voice_service_stub.h | 30 + .../server/utils/history_info_mgr.cpp | 65 ++ .../server/utils/history_info_mgr.h | 40 + .../server/utils/service_db_helper.cpp | 76 ++ .../server/utils/service_db_helper.h | 35 + .../server/utils/switch_observer.cpp | 35 + .../server/utils/switch_observer.h | 37 + .../server/utils/switch_provider.cpp | 110 +++ .../server/utils/switch_provider.h | 43 + .../server/utils/system_event_observer.cpp | 103 +++ .../server/utils/system_event_observer.h | 45 + .../server/wakeup/wakeup_adapter_listener.cpp | 93 ++ .../server/wakeup/wakeup_adapter_listener.h | 48 + .../server/wakeup/wakeup_engine.cpp | 337 +++++++ .../server/wakeup/wakeup_engine.h | 62 ++ ..._intell_voice_trigger_connector_callback.h | 33 + ..._intell_voice_trigger_connector_internal.h | 37 + .../i_intell_voice_trigger_connector_module.h | 36 + .../connector_mgr/trigger_callback_impl.cpp | 40 + .../connector_mgr/trigger_callback_impl.h | 38 + .../connector_mgr/trigger_connector.cpp | 392 +++++++++ .../server/connector_mgr/trigger_connector.h | 135 +++ .../trigger_connector_common_type.h | 31 + .../trigger_connector_internal_impl.cpp | 80 ++ .../trigger_connector_internal_impl.h | 41 + .../trigger_connector_internal_validation.cpp | 137 +++ .../trigger_connector_internal_validation.h | 81 ++ .../connector_mgr/trigger_connector_mgr.cpp | 59 ++ .../connector_mgr/trigger_connector_mgr.h | 43 + .../i_intell_voice_trigger_adapter_listener.h | 30 + ...i_intell_voice_trigger_detector_callback.h | 42 + ...ntell_voice_trigger_recognition_callback.h | 38 + .../server/trigger_base_type.cpp | 65 ++ .../server/trigger_base_type.h | 84 ++ .../server/trigger_db_helper.cpp | 205 +++++ .../server/trigger_db_helper.h | 46 + .../server/trigger_detector.cpp | 60 ++ .../server/trigger_detector.h | 41 + .../server/trigger_detector_callback.cpp | 41 + .../server/trigger_detector_callback.h | 35 + .../trigger_detector_recognition_callback.cpp | 47 + .../trigger_detector_recognition_callback.h | 37 + .../server/trigger_helper.cpp | 314 +++++++ .../server/trigger_helper.h | 91 ++ .../server/trigger_manager.cpp | 102 +++ .../server/trigger_manager.h | 51 ++ .../server/trigger_service.cpp | 115 +++ .../server/trigger_service.h | 40 + tests/BUILD.gn | 26 + tests/fuzztest/Calculator_fuzzer/BUILD.gn | 35 + .../Calculator_fuzzer/Calculator_fuzzer.cpp | 50 ++ .../Calculator_fuzzer/Calculator_fuzzer.h | 21 + tests/fuzztest/Calculator_fuzzer/corpus/init | 13 + tests/fuzztest/Calculator_fuzzer/project.xml | 25 + tests/unittest/intell_voice_test/BUILD.gn | 110 +++ .../include/engine_event_callback.h | 45 + .../include/wait_for_result.h | 36 + .../src/client_unit_test.cpp | 109 +++ .../src/engine_event_callback.cpp | 100 +++ .../src/trigger_manager_test.cpp | 107 +++ .../src/trigger_unit_test.cpp | 89 ++ .../intell_voice_test/src/wait_for_result.cpp | 38 + utils/BUILD.gn | 68 ++ utils/base_constants.h | 32 + utils/base_thread.cpp | 79 ++ utils/base_thread.h | 47 + utils/intell_voice_generic_factory.h | 75 ++ utils/intell_voice_log.h | 36 + utils/memory_guard.cpp | 42 + utils/memory_guard.h | 27 + utils/message_queue.cpp | 162 ++++ utils/message_queue.h | 77 ++ utils/msg_handle_thread.cpp | 132 +++ utils/msg_handle_thread.h | 52 ++ utils/scope_guard.h | 97 +++ utils/string_util.cpp | 143 +++ utils/string_util.h | 131 +++ utils/time_util.cpp | 183 ++++ utils/time_util.h | 102 +++ 159 files changed, 14300 insertions(+) create mode 100755 LICENSE create mode 100755 OAT.xml create mode 100755 README_zh.md create mode 100755 bundle.json create mode 100755 figures/intelligent-voice-framework.png create mode 100755 frameworks/js/BUILD.gn create mode 100755 frameworks/js/napi/engine_event_callback_napi.cpp create mode 100755 frameworks/js/napi/engine_event_callback_napi.h create mode 100755 frameworks/js/napi/enroll_intell_voice_engine_callback_napi.cpp create mode 100755 frameworks/js/napi/enroll_intell_voice_engine_callback_napi.h create mode 100755 frameworks/js/napi/enroll_intell_voice_engine_napi.cpp create mode 100755 frameworks/js/napi/enroll_intell_voice_engine_napi.h create mode 100755 frameworks/js/napi/intell_voice_manager_napi.cpp create mode 100755 frameworks/js/napi/intell_voice_manager_napi.h create mode 100755 frameworks/js/napi/intell_voice_napi_queue.cpp create mode 100755 frameworks/js/napi/intell_voice_napi_queue.h create mode 100755 frameworks/js/napi/intell_voice_napi_util.cpp create mode 100755 frameworks/js/napi/intell_voice_napi_util.h create mode 100755 frameworks/js/napi/wakeup_intell_voice_engine_napi.cpp create mode 100755 frameworks/js/napi/wakeup_intell_voice_engine_napi.h create mode 100755 frameworks/native/BUILD.gn create mode 100755 frameworks/native/enroll_intell_voice_engine.cpp create mode 100755 frameworks/native/intell_voice_manager.cpp create mode 100755 frameworks/native/wakeup_intell_voice_engine.cpp create mode 100755 interfaces/inner_api/native/enroll_intell_voice_engine.h create mode 100755 interfaces/inner_api/native/intell_voice_info.h create mode 100755 interfaces/inner_api/native/intell_voice_manager.h create mode 100755 interfaces/inner_api/native/wakeup_intell_voice_engine.h create mode 100755 interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts create mode 100755 llt/hdt/CMakeLists.txt create mode 100755 llt/hdt/build.sh create mode 100755 llt/hdt/depend_libs/cmake/CMakeLists.txt create mode 100755 llt/hdt/depend_libs/cmake/libhilog.cmake create mode 100755 llt/hdt/depend_libs/cmake/libsec.cmake create mode 100755 llt/hdt/depend_libs/cmake/libutilsbase.cmake create mode 100755 llt/hdt/depend_libs/src/file_ex.cpp create mode 100755 llt/hdt/run.sh create mode 100755 llt/hdt/stub/message_parcel.cpp create mode 100755 llt/hdt/testcase/intell_voice_utils/test_time_util.cpp create mode 100755 sa_profile/2688.xml create mode 100755 sa_profile/BUILD.gn create mode 100755 services/BUILD.gn create mode 100755 services/etc/BUILD.gn create mode 100755 services/etc/intell_voice_service.cfg create mode 100755 services/etc/intell_voice_service.rc create mode 100755 services/intell_voice_engine/i_intell_voice_engine.h create mode 100755 services/intell_voice_engine/i_intell_voice_engine_callback.h create mode 100755 services/intell_voice_engine/i_intell_voice_service.h create mode 100755 services/intell_voice_engine/proxy/engine_callback_inner.cpp create mode 100755 services/intell_voice_engine/proxy/engine_callback_inner.h create mode 100755 services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.cpp create mode 100755 services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.h create mode 100755 services/intell_voice_engine/proxy/intell_voice_engine_proxy.cpp create mode 100755 services/intell_voice_engine/proxy/intell_voice_engine_proxy.h create mode 100755 services/intell_voice_engine/proxy/intell_voice_service_proxy.cpp create mode 100755 services/intell_voice_engine/proxy/intell_voice_service_proxy.h create mode 100755 services/intell_voice_engine/server/base/adapter_callback_service.cpp create mode 100755 services/intell_voice_engine/server/base/adapter_callback_service.h create mode 100755 services/intell_voice_engine/server/base/audio_source.cpp create mode 100755 services/intell_voice_engine/server/base/audio_source.h create mode 100755 services/intell_voice_engine/server/base/engine_base.cpp create mode 100755 services/intell_voice_engine/server/base/engine_base.h create mode 100755 services/intell_voice_engine/server/base/engine_factory.cpp create mode 100755 services/intell_voice_engine/server/base/engine_factory.h create mode 100755 services/intell_voice_engine/server/base/file_source.cpp create mode 100755 services/intell_voice_engine/server/base/file_source.h create mode 100755 services/intell_voice_engine/server/base/intell_voice_adapter_listener.h create mode 100755 services/intell_voice_engine/server/enroll/enroll_adapter_listener.cpp create mode 100755 services/intell_voice_engine/server/enroll/enroll_adapter_listener.h create mode 100755 services/intell_voice_engine/server/enroll/enroll_engine.cpp create mode 100755 services/intell_voice_engine/server/enroll/enroll_engine.h create mode 100755 services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.cpp create mode 100755 services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.h create mode 100755 services/intell_voice_engine/server/sa/intell_voice_engine_stub.cpp create mode 100755 services/intell_voice_engine/server/sa/intell_voice_engine_stub.h create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service.cpp create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service.h create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service_manager.cpp create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service_manager.h create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service_stub.cpp create mode 100755 services/intell_voice_engine/server/sa/intell_voice_service_stub.h create mode 100755 services/intell_voice_engine/server/utils/history_info_mgr.cpp create mode 100755 services/intell_voice_engine/server/utils/history_info_mgr.h create mode 100755 services/intell_voice_engine/server/utils/service_db_helper.cpp create mode 100755 services/intell_voice_engine/server/utils/service_db_helper.h create mode 100755 services/intell_voice_engine/server/utils/switch_observer.cpp create mode 100755 services/intell_voice_engine/server/utils/switch_observer.h create mode 100755 services/intell_voice_engine/server/utils/switch_provider.cpp create mode 100755 services/intell_voice_engine/server/utils/switch_provider.h create mode 100755 services/intell_voice_engine/server/utils/system_event_observer.cpp create mode 100755 services/intell_voice_engine/server/utils/system_event_observer.h create mode 100755 services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.cpp create mode 100755 services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.h create mode 100755 services/intell_voice_engine/server/wakeup/wakeup_engine.cpp create mode 100755 services/intell_voice_engine/server/wakeup/wakeup_engine.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_callback.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_internal.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_module.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.cpp create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector.cpp create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_common_type.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.cpp create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.cpp create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.h create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.cpp create mode 100755 services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.h create mode 100755 services/intell_voice_trigger/server/i_intell_voice_trigger_adapter_listener.h create mode 100755 services/intell_voice_trigger/server/i_intell_voice_trigger_detector_callback.h create mode 100755 services/intell_voice_trigger/server/i_intell_voice_trigger_recognition_callback.h create mode 100755 services/intell_voice_trigger/server/trigger_base_type.cpp create mode 100755 services/intell_voice_trigger/server/trigger_base_type.h create mode 100755 services/intell_voice_trigger/server/trigger_db_helper.cpp create mode 100755 services/intell_voice_trigger/server/trigger_db_helper.h create mode 100755 services/intell_voice_trigger/server/trigger_detector.cpp create mode 100755 services/intell_voice_trigger/server/trigger_detector.h create mode 100755 services/intell_voice_trigger/server/trigger_detector_callback.cpp create mode 100755 services/intell_voice_trigger/server/trigger_detector_callback.h create mode 100755 services/intell_voice_trigger/server/trigger_detector_recognition_callback.cpp create mode 100755 services/intell_voice_trigger/server/trigger_detector_recognition_callback.h create mode 100755 services/intell_voice_trigger/server/trigger_helper.cpp create mode 100755 services/intell_voice_trigger/server/trigger_helper.h create mode 100755 services/intell_voice_trigger/server/trigger_manager.cpp create mode 100755 services/intell_voice_trigger/server/trigger_manager.h create mode 100755 services/intell_voice_trigger/server/trigger_service.cpp create mode 100755 services/intell_voice_trigger/server/trigger_service.h create mode 100755 tests/BUILD.gn create mode 100755 tests/fuzztest/Calculator_fuzzer/BUILD.gn create mode 100755 tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.cpp create mode 100755 tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.h create mode 100755 tests/fuzztest/Calculator_fuzzer/corpus/init create mode 100755 tests/fuzztest/Calculator_fuzzer/project.xml create mode 100755 tests/unittest/intell_voice_test/BUILD.gn create mode 100755 tests/unittest/intell_voice_test/include/engine_event_callback.h create mode 100755 tests/unittest/intell_voice_test/include/wait_for_result.h create mode 100755 tests/unittest/intell_voice_test/src/client_unit_test.cpp create mode 100755 tests/unittest/intell_voice_test/src/engine_event_callback.cpp create mode 100755 tests/unittest/intell_voice_test/src/trigger_manager_test.cpp create mode 100755 tests/unittest/intell_voice_test/src/trigger_unit_test.cpp create mode 100755 tests/unittest/intell_voice_test/src/wait_for_result.cpp create mode 100755 utils/BUILD.gn create mode 100755 utils/base_constants.h create mode 100755 utils/base_thread.cpp create mode 100755 utils/base_thread.h create mode 100755 utils/intell_voice_generic_factory.h create mode 100755 utils/intell_voice_log.h create mode 100755 utils/memory_guard.cpp create mode 100755 utils/memory_guard.h create mode 100755 utils/message_queue.cpp create mode 100755 utils/message_queue.h create mode 100755 utils/msg_handle_thread.cpp create mode 100755 utils/msg_handle_thread.h create mode 100755 utils/scope_guard.h create mode 100755 utils/string_util.cpp create mode 100755 utils/string_util.h create mode 100755 utils/time_util.cpp create mode 100755 utils/time_util.h diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..4947287 --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + 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/OAT.xml b/OAT.xml new file mode 100755 index 0000000..d298c05 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 0000000..64b2e18 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,195 @@ +# 智能语音组件 + +## 概述 + +### 功能简介 + +智能语音组件包括智能语音服务框架和智能语音驱动,主要实现了语音注册及语音唤醒相关功能。 + +**图 1** 智能语音组件架构图 + +![image.png](figures/intelligent-voice-framework.png) + +智能语音服务框架支持如下功能: +系统事件监测:开机解锁、亮灭屏等系统事件监测 +并发策略:智能语音业务并发管理 +智能语音业务:语音注册、语音唤醒等智能语音业务处理 +声音触发器:DSP模型加载、DSP算法启停、DSP事件处理 + +智能语音驱动支持如下功能: +引擎算法:智能语音算法引擎以及事件上报 +设备驱动:DSP模型加载卸载、算法启停、事件上报以及硬件相关通路配置 + +### 基本概念 +- 语音注册:将用户说的唤醒词转换为声学模型以及声纹特征,以便后续的语音唤醒。 +- 语音唤醒:判断当前说话人是否为已注册的特定用户。 +- DSP:数字信号处理器(Digital Signal Processors),DSP芯片即指能够实现数字信号处理技术的芯片。 + +### 目录结构 + +仓目录结构如下: + +```shell +/foundation/ai/intelligent_voice_framework # 智能音频组件业务代码 +├── frameworks # 框架代码 +│ ├── native # 内部接口实现 +│ └── js # 外部接口实现 +├── interfaces # 接口代码 +│ ├── inner_api # 内部接口 +│ └── kits # 外部接口 +├── sa_profile # 服务配置文件 +├── services # 服务代码 +├── LICENSE # 证书文件 +├── tests # 开发者测试 +└── utils # 公共函数 +``` + +### 约束与限制 + +- 智能语音服务当前只支持一个唤醒词的注册以及唤醒。 + + +## 接口说明 +### 语音注册接口说明 + +|接口名称|接口描述| +|---|---| +|createEnrollIntelligentVoiceEngine(descriptor: EnrollIntelligentVoiceEngineDescriptor): EnrollIntelligentVoiceEngine|创建注册引擎。| +|init(config: EnrollEngineConfig): EnrollIntelligentVoiceEngineCallbackInfo|初始化注册引擎。| +|start(isLast: boolean): EnrollIntelligentVoiceEngineCallbackInfo|启动注册。| +|stop(): void|停止注册。| +|commit(): EnrollIntelligentVoiceEngineCallbackInfo|确认注册结果。| +|setWakeupHapInfo(info: WakeupHapInfo): void|设置唤醒应用信息。| +|setSensibility(sensibility: SensibilityType): void|设置灵敏度。| +|release(): void|释放注册引擎。| + +### 语音唤醒接口说明 + +|接口名称|接口描述| +|---|---| +|createWakeupIntelligentVoiceEngine(descriptor: WakeupIntelligentVoiceEngineDescriptor): WakeupIntelligentVoiceEngine|创建唤醒引擎。| +|setWakeupHapInfo(info: WakeupHapInfo): void|设置唤醒应用信息。| +|setSensibility(sensibility: SensibilityType): void|设置灵敏度。| +|on(type: 'wakeupIntelligentVoiceEvent', callback: Callback): void|订阅唤醒事件。| +|release(): void|释放唤醒引擎。| + + +## 开发实例 + +### 语音注册 + +语音注册流程是用户通过应用的注册界面主动发起的交互流程,主要流程如下: +1. 用户启动注册(创建注册引擎并初始化注册引擎)后,进入注册界面。 +2. 界面提示用户说出唤醒词,用户根据提示说出相应唤醒词(启动注册),界面会让用户再次重复说出唤醒词,直到最后一次。 +3. 注册完成(确认注册结果)后,注册流程全部完成。 +示例代码如下: + +```js +// 引入智能音频 +import intelligentVoice from '@ohos.ai.intelligentVoice'; + +// 获取智能音频管理服务 +var manager = intellVoice.getIntelligentVoiceManager(); +if (manager == null) { + console.error("Get IntelligentVoiceManager failed."); +} else { + console.info("Get IntelligentVoiceManager success."); + return; +} + +// 创建注册引擎 +var engine = null; +let engineDescriptor = { + wakeupPhrase: '', // 设置唤醒词 +} +await intellVoice.createEnrollIntelligentVoiceEngine(engineDescriptor).then((data) => { + engine = data; + console.info('Create EnrollIntelligentVoice Engine finish'); +}).catch((err) => { + console.error('Create EnrollIntelligentVoice Engine failed, err: ' + err.message); +}); +if (engine == null) { + console.error('Create EnrollIntelligentVoice Engine failed'); + return; +} + +// 初始化注册引擎 +let config = { + language: "zh", // 中文 + area: "CN", // 中国 +} +engine.init(config).then((data) => { + console.info('Init EnrollIntelligentVoice Engine finish'); +}).catch((err) => { + console.info('Init EnrollIntelligentVoice Engine failed, err: '+ err.message); +}); + +// 启动注册 +let isLast = true; // true: 最后一次启动,false: 非最后一次启动,实例为true +engine.start(isLast).then((data) => { + console.info('Start enrollment finish'); +}).catch((err) => { + console.info('Start enrollment failed, err: '+ err.message); +}); + +// 确认注册结果 +engine.commit().then((data) => { + console.info('Commit enroll result finish'); +}).catch((err) => { + console.info('Commit enroll result failed, err: '+ err.message); +}); + +// 下发语音唤醒应用信息 +let info = { + bundleName: "demo", // 应用的bundle name,demo只是个参考例子,具体填写由应用确定 + abilityName: "demo", // 应用的ability name,demo只是个参考例子,具体填写由应用确定 +} +engine.setWakeupHapInfo(info).then((data) => { + console.info('Set wakeup hap info finish'); +}).catch((err) => { + console.info('Set wakeup hap info failed, err: '+ err.message); +}); + +// 释放注册引擎 +engine.release().then((data) => { + console.info('Release EnrollIntelligentVoice engine success.'); +}).catch((err) => { + console.info('Release EnrollIntelligentVoice engine failed, err: '+ err.message); +}); +``` + +### 语音唤醒 + +语言唤醒由智能语音组件控制,上层应用只需要调用`createWakeupIntelligentVoiceEngine`获取唤醒引擎后注册唤醒事件回调即可。 + +```js +// 获取唤醒引擎 +var engine = null; +let engineDescriptor = { + needApAlgEngine: true, // 是否需要框架提供ap侧算法引擎 + wakeupPhrase: '', // 设置唤醒词 +} +await intellVoice.createWakeupIntelligentVoiceEngine(engineDescriptor).then((data) => { + engine = data; + console.info('Create WakeupIntelligentVoice Engine finish'); +}).catch((err) => { + console.error('Create WakeupIntelligentVoice Engine failed, err: ' + err.message); +}); +if (engine == null) { + console.error('Create WakeupIntelligentVoice Engine failed'); + return; +} + +// 注册事件回调 +engine.on('wakeupIntelligentVoiceEvent',(callback) => { + console.info('wakeupIntelligentVoiceEvent CallBackInfo:') + for (let prop in callback) { + console.info('wakeupIntelligentVoiceEvent prop: ' + prop); + console.info('wakeupIntelligentVoiceEvent value: ' + callback[prop]); + } +}); +``` + +## 相关仓 + +intelligent_voice_framework diff --git a/bundle.json b/bundle.json new file mode 100755 index 0000000..3963be1 --- /dev/null +++ b/bundle.json @@ -0,0 +1,57 @@ +{ + "name": "@ohos/intelligent_voice_framework", + "description": "intelligent_voice framework", + "version": "1.0", + "license": "Apache License 2.0", + "publishAs": "code-segment", + "segment": { + "destPath": "foundation/ai/intelligent_voice_framework" + }, + "component": { + "name": "intelligent_voice_framework", + "subsystem": "ai", + "syscap": [ + "SystemCapability.AI.IntelligentVoice.Core" + ], + "adapter_system_type": ["standard"], + "rom": "", + "ram": "", + "deps": { + "components": ["intelligent_voice_framework"], + "third_party": [] + }, + "features": [ + ], + "build": { + "sub_component": [ + "//foundation/ai/intelligent_voice_framework/services:intell_voice_server", + "//foundation/ai/intelligent_voice_framework/services:intell_voice_proxy", + "//foundation/ai/intelligent_voice_framework/services/etc:intell_voice_service.rc", + "//foundation/ai/intelligent_voice_framework/frameworks/js:intelligentvoice", + "//foundation/ai/intelligent_voice_framework/frameworks/js:intelligentvoice_js", + "//foundation/ai/intelligent_voice_framework/frameworks/native:intellvoice_native", + "//foundation/ai/intelligent_voice_framework/sa_profile:intell_voice_service_sa_profile" + ], + "inner_kits": [ + { + "type": "none", + "name": "//foundation/ai/intelligent_voice_framework/frameworks/js:intelligentvoice_js", + "header": { + "header_files": [ + "intell_voice_manager_napi.h", + "intell_voice_engine_napi.h", + "enroll_intell_voice_engine_napi.h" + ], + "header_base": [ + "//foundation/ai/intelligent_voice_framework/frameworks/js/napi/include" + ] + } + } + ], + "test": [ + "//foundation/ai/intelligent_voice_framework/tests:intell_voice_unit_test", + "//foundation/ai/intelligent_voice_framework/tests:intell_voice_fuzz_test" + ] + } + } +} diff --git a/figures/intelligent-voice-framework.png b/figures/intelligent-voice-framework.png new file mode 100755 index 0000000000000000000000000000000000000000..d17672019fd8b08dcdc3ede9859691dfbdb5a196 GIT binary patch literal 55004 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

8QZ<_q@NzdpE}r5 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 literal 0 HcmV?d00001 diff --git a/frameworks/js/BUILD.gn b/frameworks/js/BUILD.gn new file mode 100755 index 0000000..be6b399 --- /dev/null +++ b/frameworks/js/BUILD.gn @@ -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 +# +# 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("//build/ohos.gni") +import("//build/ohos/ace/ace.gni") + +js_declaration("intelligentvoice_js") { + part_name = "intelligent_voice_framework" + sources = [ "//foundation/ai/intelligent_voice_framework/interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts" ] +} + +ohos_copy("intelligentvoice_declaration") { + sources = [ "//foundation/ai/intelligent_voice_framework/interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts" ] + outputs = [ target_out_dir + "/$target_name/" ] + module_source_dir = target_out_dir + "/$target_name" + module_install_name = "" +} + +ohos_shared_library("intelligentvoice") { + sources = [ + "napi/engine_event_callback_napi.cpp", + "napi/enroll_intell_voice_engine_callback_napi.cpp", + "napi/enroll_intell_voice_engine_napi.cpp", + "napi/intell_voice_manager_napi.cpp", + "napi/intell_voice_napi_queue.cpp", + "napi/intell_voice_napi_util.cpp", + "napi/wakeup_intell_voice_engine_napi.cpp", + ] + + include_dirs = [ + "//foundation/arkui/napi/interfaces/kits", + "//foundation/ai/intelligent_voice_framework/interfaces/inner_api/native", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine/proxy", + "//foundation/ai/intelligent_voice_framework/utils", + "napi", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//foundation/ai/intelligent_voice_framework/frameworks/native:intellvoice_native", + "//foundation/ai/intelligent_voice_framework/services:intell_voice_proxy", + "//foundation/arkui/napi:ace_napi", + ] + + external_deps = [ + "ability_base:want", + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + relative_install_dir = "module/ai" + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} diff --git a/frameworks/js/napi/engine_event_callback_napi.cpp b/frameworks/js/napi/engine_event_callback_napi.cpp new file mode 100755 index 0000000..e0683b2 --- /dev/null +++ b/frameworks/js/napi/engine_event_callback_napi.cpp @@ -0,0 +1,118 @@ +/* + * 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. + */ + +#include "engine_event_callback_napi.h" +#include +#include "intell_voice_log.h" + +using namespace std; +using namespace OHOS::IntellVoiceEngine; +#define LOG_TAG "EngineEventCallbackNapi" + +namespace OHOS { +namespace IntellVoiceNapi { +EngineEventCallbackNapi::EngineEventCallbackNapi(napi_env env, napi_value callback) +{ + INTELL_VOICE_LOG_INFO("enter"); + env_ = env; + if (env_ != nullptr) { + napi_get_uv_event_loop(env_, &loop_); + } + callbackRef_ = make_shared(env_, callback); +} + +EngineEventCallbackNapi::~EngineEventCallbackNapi() +{ + INTELL_VOICE_LOG_INFO("enter"); + callbackRef_ = nullptr; +} + +void EngineEventCallbackNapi::OnEvent(const IntellVoiceEngineCallBackEvent &event) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (callbackRef_ == nullptr) { + INTELL_VOICE_LOG_ERROR("Failed to get engine event callback"); + return; + } + + EngineCallBackInfo cbInfo = {event.msgId, event.result, event.info}; + + INTELL_VOICE_LOG_INFO("OnEvent EngineCallBackInfo: msgId: %{public}d, errCode: %{public}d, context: %{public}s", + cbInfo.msgId, + cbInfo.errCode, + cbInfo.context.c_str()); + + return OnEventUvCallback(cbInfo); +} + +void EngineEventCallbackNapi::OnEventUvCallback(EngineCallBackInfo &cbInfo) +{ + CHECK_RETURN_VOID(loop_ != nullptr, "loop is nullptr"); + uv_work_t *work = new (nothrow) uv_work_t; + CHECK_RETURN_VOID(work != nullptr, "Create uv work failed, no memory"); + + work->data = new EngineEventUvCallback {env_, cbInfo, callbackRef_}; + + uv_queue_work( + loop_, + work, + [](uv_work_t *work) {}, + [](uv_work_t *work, int uvStatus) { + shared_ptr uvCallback( + static_cast(work->data), [work](EngineEventUvCallback *data) { + delete data; + delete work; + }); + CHECK_RETURN_VOID(uvCallback != nullptr, "uvCallback is nullptr"); + CHECK_RETURN_VOID(uvCallback->callback != nullptr, "uvCallback callback is nullptr"); + napi_env env = uvCallback->env_; + INTELL_VOICE_LOG_INFO("uv_queue_work start"); + + napi_value jsCallback = uvCallback->callback->GetRefValue(); + if (jsCallback == nullptr) { + INTELL_VOICE_LOG_ERROR("get reference value fail"); + return; + } + + const size_t argc = 1; + napi_value args[argc] = {nullptr}; + GetJsCallbackInfo(env, uvCallback->cbInfo, args[0]); + if (args[0] == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to create engine event callback"); + return; + } + + napi_value result = nullptr; + napi_status status = napi_call_function(env, nullptr, jsCallback, argc, args, &result); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to call engine event callback, error: %{public}d", status); + } + }); +} + +void GetJsCallbackInfo(const napi_env &env, const EngineCallBackInfo &callbackInfo, napi_value &jsObj) +{ + napi_status status = napi_create_object(env, &jsObj); + if (status != napi_ok || jsObj == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to create js callbackInfo, error: %{public}d", status); + return; + } + + napi_set_named_property(env, jsObj, "msgId", SetValue(env, callbackInfo.msgId)); + napi_set_named_property(env, jsObj, "errCode", SetValue(env, callbackInfo.errCode)); + napi_set_named_property(env, jsObj, "context", SetValue(env, callbackInfo.context)); +} +} // namespace IntellVoiceNapi +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/engine_event_callback_napi.h b/frameworks/js/napi/engine_event_callback_napi.h new file mode 100755 index 0000000..145662d --- /dev/null +++ b/frameworks/js/napi/engine_event_callback_napi.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 + * + * 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. + */ + +#ifndef ENGINE_EVENT_CALLBACK_H +#define ENGINE_EVENT_CALLBACK_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "intell_voice_napi_util.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceNapi { +using OHOS::IntellVoiceEngine::IIntellVoiceEngineEventCallback; +using OHOS::IntellVoiceEngine::IntellVoiceEngineCallBackEvent; + +struct EngineCallBackInfo { + int32_t msgId; + int32_t errCode; + std::string context; +}; + +class EngineEventCallbackNapi : public IIntellVoiceEngineEventCallback { +public: + explicit EngineEventCallbackNapi(napi_env env, napi_value callback); + virtual ~EngineEventCallbackNapi(); + + void OnEvent(const IntellVoiceEngineCallBackEvent &event) override; + +private: + struct EngineEventUvCallback { + napi_env env_ = nullptr; + EngineCallBackInfo cbInfo; + std::shared_ptr callback; + }; + + void OnEventUvCallback(EngineCallBackInfo &cbInfo); + + napi_env env_ = nullptr; + uv_loop_s *loop_ = nullptr; + std::shared_ptr callbackRef_ = nullptr; +}; + +void GetJsCallbackInfo(const napi_env &env, const EngineCallBackInfo &callbackInfo, napi_value &jsObj); +} // namespace IntellVoiceNapi +} // namespace OHOS +#endif diff --git a/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.cpp b/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.cpp new file mode 100755 index 0000000..53c63f6 --- /dev/null +++ b/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.cpp @@ -0,0 +1,152 @@ +/* + * 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. + */ + +#include "enroll_intell_voice_engine_callback_napi.h" +#include "intell_voice_log.h" + +using namespace std; +using namespace OHOS::IntellVoiceEngine; +#define LOG_TAG "EnrollIntellVoiceEngineCallbackNapi" + +namespace OHOS { +namespace IntellVoiceNapi { +void EnrollIntellVoiceEngineCallBackInfo::GetCallBackInfoNapiValue(const napi_env &env, napi_value &result) +{ + napi_status status = napi_create_object(env, &result); + if (status != napi_ok || result == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to create js callbackInfo, error: %{public}d", status); + return; + } + + napi_set_named_property(env, result, "eventId", SetValue(env, eventId)); + napi_set_named_property(env, result, "errCode", SetValue(env, errCode)); + napi_set_named_property(env, result, "context", SetValue(env, context)); +} + +EnrollIntellVoiceEngineCallbackNapi::EnrollIntellVoiceEngineCallbackNapi(const napi_env env) +{ + env_ = env; + contextMap_.clear(); +} + +EnrollIntellVoiceEngineCallbackNapi::~EnrollIntellVoiceEngineCallbackNapi() +{ + contextMap_.clear(); +} + +void EnrollIntellVoiceEngineCallbackNapi::QueueAsyncWork(EnrollAsyncContext *context) +{ + std::lock_guard lock(mutex_); + if (contextMap_.find(context->type) == contextMap_.end()) { + std::queue contextQue; + contextQue.push(context); + contextMap_[context->type] = contextQue; + } else { + contextMap_.at(context->type).push(context); + } +} + +void EnrollIntellVoiceEngineCallbackNapi::ClearAsyncWork(bool error, const std::string &msg) +{ + INTELL_VOICE_LOG_INFO("%{public}s", msg.c_str()); + std::lock_guard lock(mutex_); + for (auto it = contextMap_.begin(); it != contextMap_.end(); it++) { + auto &contextQue = it->second; + while (!contextQue.empty()) { + EnrollAsyncContext *context = contextQue.front(); + contextQue.pop(); + if (error) { + INTELL_VOICE_LOG_WARN("error occured"); + } + OnJsCallBack(context); + } + } + contextMap_.clear(); +} + +void EnrollIntellVoiceEngineCallbackNapi::OnEvent(const IntellVoiceEngineCallBackEvent &event) +{ + INTELL_VOICE_LOG_INFO("OnEvent: msgId: %{public}d, errCode: %{public}d, context: %{public}s", + event.msgId, + event.result, + event.info.c_str()); + EnrollAsyncWorkType asyncType = ASYNC_WORK_INVALID; + switch (event.msgId) { + case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_INIT_DONE: + asyncType = ASYNC_WORK_INIT; + break; + case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE: + asyncType = ASYNC_WORK_START; + break; + case HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE: + asyncType = ASYNC_WORK_COMMIT; + break; + default: + break; + } + if (contextMap_.find(asyncType) == contextMap_.end() || contextMap_.at(asyncType).empty()) { + INTELL_VOICE_LOG_ERROR("callback is called, But context is empty"); + return; + } + + EnrollAsyncContext *context = contextMap_.at(asyncType).front(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("context is nullptr"); + return; + } + contextMap_.at(asyncType).pop(); + + context->callbackInfo = {event.msgId, event.result, event.info}; + OnJsCallBack(context); +} + +void EnrollIntellVoiceEngineCallbackNapi::UvWorkCallBack(uv_work_t *work, int status) +{ + INTELL_VOICE_LOG_INFO("enter"); + auto asyncContext = reinterpret_cast(work->data); + napi_value result = nullptr; + if (asyncContext != nullptr) { + napi_env env = asyncContext->env_; + asyncContext->callbackInfo.GetCallBackInfoNapiValue(env, result); + NapiAsync::CommonCallbackRoutine(asyncContext, result); + } + delete work; +} + +void EnrollIntellVoiceEngineCallbackNapi::OnJsCallBack(EnrollAsyncContext *context) +{ + INTELL_VOICE_LOG_INFO("enter"); + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env_, &loop); + if (loop != nullptr) { + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work != nullptr) { + work->data = reinterpret_cast(context); + int ret = uv_queue_work( + loop, work, [](uv_work_t *work) {}, UvWorkCallBack); + if (ret != 0) { + INTELL_VOICE_LOG_INFO("Failed to execute libuv work queue"); + delete context; + delete work; + } + } else { + delete context; + } + } else { + delete context; + } +} +} // namespace IntellVoiceNapi +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.h b/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.h new file mode 100755 index 0000000..0ffd197 --- /dev/null +++ b/frameworks/js/napi/enroll_intell_voice_engine_callback_napi.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#ifndef ENROLL_INTELL_VOICE_ENGINE_CALLBACK_NAPI_H +#define ENROLL_INTELL_VOICE_ENGINE_CALLBACK_NAPI_H + +#include +#include +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "intell_voice_napi_util.h" +#include "i_intell_voice_engine_callback.h" +#include "intell_voice_napi_queue.h" + +namespace OHOS { +namespace IntellVoiceNapi { +using OHOS::IntellVoiceEngine::IIntellVoiceEngineEventCallback; +using OHOS::IntellVoiceEngine::IntellVoiceEngineCallBackEvent; + +using ProcessWorkFunc = std::function; + +enum EnrollAsyncWorkType { + ASYNC_WORK_INIT = 0, + ASYNC_WORK_START, + ASYNC_WORK_COMMIT, + ASYNC_WORK_INVALID, +}; + +struct EnrollIntellVoiceEngineCallBackInfo { + int32_t eventId; + int32_t errCode; + std::string context; + + void GetCallBackInfoNapiValue(const napi_env &env, napi_value &result); +}; + +class EnrollAsyncContext : public AsyncContext { +public: + EnrollAsyncWorkType type = ASYNC_WORK_INVALID; + ProcessWorkFunc processWork = nullptr; + EnrollIntellVoiceEngineCallBackInfo callbackInfo; +}; + +class EnrollIntellVoiceEngineCallbackNapi : public IIntellVoiceEngineEventCallback { +public: + explicit EnrollIntellVoiceEngineCallbackNapi(const napi_env env); + virtual ~EnrollIntellVoiceEngineCallbackNapi(); + + void OnEvent(const IntellVoiceEngineCallBackEvent &event) override; + void QueueAsyncWork(EnrollAsyncContext *context); + void ClearAsyncWork(bool error, const std::string &msg); + +private: + void OnJsCallBack(EnrollAsyncContext *context); + static void UvWorkCallBack(uv_work_t *work, int status); + +private: + std::mutex mutex_; + napi_env env_ = nullptr; + + std::map> contextMap_; +}; +} // namespace IntellVoiceNapi +} // namespace OHOS +#endif diff --git a/frameworks/js/napi/enroll_intell_voice_engine_napi.cpp b/frameworks/js/napi/enroll_intell_voice_engine_napi.cpp new file mode 100755 index 0000000..dd19ee9 --- /dev/null +++ b/frameworks/js/napi/enroll_intell_voice_engine_napi.cpp @@ -0,0 +1,504 @@ +/* + * 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. + */ + +#include "enroll_intell_voice_engine_napi.h" + +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "intell_voice_napi_util.h" +#include "intell_voice_napi_queue.h" +#include "intell_voice_log.h" +#include "i_intell_voice_engine_callback.h" + +#define LOG_TAG "EnrollEngineNapi" + +using namespace OHOS::IntellVoice; +using namespace std; + +namespace OHOS { +namespace IntellVoiceNapi { +EnrollIntellVoiceEngineNapi::EnrollIntellVoiceEngineNapi() +{ + INTELL_VOICE_LOG_INFO("enter, %{public}p", this); +} + +EnrollIntellVoiceEngineNapi::~EnrollIntellVoiceEngineNapi() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (wrapper_ != nullptr) { + napi_delete_reference(env_, wrapper_); + } +} + +napi_value EnrollIntellVoiceEngineNapi::New(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_value jsThis = nullptr; + napi_value undefinedResult = nullptr; + napi_get_undefined(env, &undefinedResult); + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr)); + + unique_ptr engineNapi = make_unique(); + if (engineNapi == nullptr) { + INTELL_VOICE_LOG_ERROR("Failed to create EnrollIntellVoiceEngineNapi, No memory."); + return undefinedResult; + } + engineNapi->env_ = env; + + EnrollIntelligentVoiceEngineDescriptor descriptor = {}; + napi_value value = nullptr; + if (napi_get_named_property(env, args[0], "wakeupPhrase", &value) == napi_ok) { + GetValue(env, value, descriptor.wakeupPhrase); + } + INTELL_VOICE_LOG_INFO("EngineDescriptor wakeupPhrase: %{public}s", descriptor.wakeupPhrase.c_str()); + + engineNapi->engine_ = std::make_shared(descriptor); + if (engineNapi->engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create intell voice engine faild."); + return undefinedResult; + } + engineNapi->callbackNapi_ = std::make_shared(env); + if (engineNapi->callbackNapi_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create intell voice engine callback faild."); + return undefinedResult; + } + engineNapi->engine_->SetCallback(engineNapi->callbackNapi_); + + auto finalize = [](napi_env env, void *data, void *hint) { + INTELL_VOICE_LOG_INFO("EnrollIntellVoiceEngineNapi finalize callback"); + if (data != nullptr) { + auto obj = static_cast(data); + delete obj; + } + }; + + NAPI_CALL( + env, napi_wrap(env, jsThis, static_cast(engineNapi.get()), finalize, nullptr, &(engineNapi->wrapper_))); + engineNapi.release(); + return jsThis; +} + +napi_value EnrollIntellVoiceEngineNapi::Constructor(napi_env env) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_status status; + napi_value constructor; + napi_get_undefined(env, &constructor); + + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getSupportedRegions", GetSupportedRegions), + DECLARE_NAPI_FUNCTION("init", Init), + DECLARE_NAPI_FUNCTION("start", Start), + DECLARE_NAPI_FUNCTION("stop", Stop), + DECLARE_NAPI_FUNCTION("setSensibility", SetSensibility), + DECLARE_NAPI_FUNCTION("setWakeupHapInfo", SetWakeupHapInfo), + DECLARE_NAPI_FUNCTION("setParameter", SetParameter), + DECLARE_NAPI_FUNCTION("getParameter", GetParameter), + DECLARE_NAPI_FUNCTION("release", Release), + DECLARE_NAPI_FUNCTION("commit", Commit), + }; + + status = napi_define_class(env, + ENROLL_ENGINE_NAPI_CLASS_NAME, + NAPI_AUTO_LENGTH, + New, + nullptr, + sizeof(properties) / sizeof(properties[0]), + properties, + &constructor); + + return constructor; +} + +napi_value EnrollIntellVoiceEngineNapi::GetSupportedRegions(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("get supported regions complete"); + napi_create_array(context->env_, &result); + napi_set_element(context->env_, result, 0, SetValue(context->env_, "CN")); + }; + + return NapiAsync::AsyncWork(context, "GetSupportedRegions", execute, complete); +} + +napi_value EnrollIntellVoiceEngineNapi::Init(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create InitContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + napi_value temp = nullptr; + if (napi_get_named_property(env, argv[0], "language", &temp) == napi_ok) { + GetValue(env, temp, + reinterpret_cast(context->engineNapi_)->config_.language); + } + if (napi_get_named_property(env, argv[0], "region", &temp) == napi_ok) { + GetValue(env, temp, + reinterpret_cast(context->engineNapi_)->config_.region); + } + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + context->type = ASYNC_WORK_INIT; + context->callbackInfo.eventId = INTELLIGENT_VOICE_EVENT_ENROLL_INIT_DONE; + context->callbackInfo.errCode = INTELLIGENT_VOICE_INIT_FAILED; + context->processWork = [&](AsyncContext *asyncContext) { + EnrollIntellVoiceEngineNapi *engineNapi = reinterpret_cast( + asyncContext->engineNapi_); + auto engine = engineNapi->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return -1; + } + return engine->Init(engineNapi->config_); + }; + + AsyncExecute execute = [](napi_env env, void *data) {}; + + return NapiAsync::AsyncWork(context, "Init", execute, CompleteCallback); +} + +napi_value EnrollIntellVoiceEngineNapi::Start(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create StartContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = GetValue(env, argv[0], + reinterpret_cast(context->engineNapi_)->isLast_); + CHECK_STATUS_RETURN_VOID(context, "Failed to get isLast"); + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + context->type = ASYNC_WORK_START; + context->callbackInfo.eventId = INTELLIGENT_VOICE_EVENT_ENROLL_COMPLETE; + context->callbackInfo.errCode = INTELLIGENT_VOICE_ENROLL_FAILED; + context->processWork = [&](AsyncContext *asyncContext) { + EnrollIntellVoiceEngineNapi *engineNapi = reinterpret_cast( + asyncContext->engineNapi_); + auto engine = engineNapi->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return -1; + } + + return engine->Start(engineNapi->isLast_); + }; + + AsyncExecute execute = [](napi_env env, void *data) {}; + + return NapiAsync::AsyncWork(context, "Start", execute, CompleteCallback); +} + +napi_value EnrollIntellVoiceEngineNapi::Stop(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + auto cb = reinterpret_cast(context->engineNapi_)->callbackNapi_; + if (cb != nullptr) { + cb->ClearAsyncWork(false, "the requests was aborted because user called stop"); + } + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->Stop(); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "Stop", execute); +} + +napi_value EnrollIntellVoiceEngineNapi::SetParameter(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 2; + class SetParameterContext : public AsyncContext { + public: + string key; + string value; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetParameterContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = GetValue(env, argv[0], context->key); + CHECK_STATUS_RETURN_VOID(context, "Failed to get key"); + context->status_ = GetValue(env, argv[1], context->value); + CHECK_STATUS_RETURN_VOID(context, "Failed to get value"); + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetParameter(asyncContext->key, asyncContext->value); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetParameter", execute); +} + +napi_value EnrollIntellVoiceEngineNapi::GetParameter(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("get parameter complete"); + result = SetValue(context->env_, "value"); + }; + return NapiAsync::AsyncWork(context, "GetParameter", execute, complete); +} + +napi_value EnrollIntellVoiceEngineNapi::SetSensibility(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class SetSensibilityContext : public AsyncContext { + public: + int32_t sensibility; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetSensibilityContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = GetValue(env, argv[0], context->sensibility); + CHECK_STATUS_RETURN_VOID(context, "Failed to get sensibility"); + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetSensibility(asyncContext->sensibility); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetSensibility", execute); +} + +napi_value EnrollIntellVoiceEngineNapi::SetWakeupHapInfo(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class SetWakeupHapContext : public AsyncContext { + public: + WakeupHapInfo hapInfo; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetWakeupHapContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + napi_value temp = nullptr; + if (napi_get_named_property(env, argv[0], "bundleName", &temp) == napi_ok) { + GetValue(env, temp, context->hapInfo.bundleName); + } + if (napi_get_named_property(env, argv[0], "abilityName", &temp) == napi_ok) { + GetValue(env, temp, context->hapInfo.abilityName); + } + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetWakeupHapInfo(asyncContext->hapInfo); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetWakeupHapInfo", execute); +} + +napi_value EnrollIntellVoiceEngineNapi::Commit(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create IntellVoiceContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + context->type = ASYNC_WORK_COMMIT; + context->callbackInfo.eventId = INTELLIGENT_VOICE_EVENT_COMMIT_ENROLL_COMPLETE; + context->callbackInfo.errCode = INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED; + context->processWork = [](AsyncContext *asyncContext) { + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return -1; + } + + return engine->Commit(); + }; + + AsyncExecute execute = [](napi_env env, void *data) {}; + + return NapiAsync::AsyncWork(context, "Commit", execute, CompleteCallback); +} + +napi_value EnrollIntellVoiceEngineNapi::Release(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto cb = reinterpret_cast(asyncContext->engineNapi_)->callbackNapi_; + if (cb != nullptr) { + cb->ClearAsyncWork(false, "the requests was aborted because user called release"); + } + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->Release(); + asyncContext->status_ = napi_ok; + reinterpret_cast(asyncContext->engineNapi_)->engine_ = nullptr; + reinterpret_cast(asyncContext->engineNapi_)->callbackNapi_ = nullptr; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("release engine complete"); + }; + return NapiAsync::AsyncWork(context, "Release", execute, complete); +} + +void EnrollIntellVoiceEngineNapi::CompleteCallback(napi_env env, napi_status status, void *data) +{ + INTELL_VOICE_LOG_INFO("enter"); + CHECK_RETURN_VOID(data != nullptr, "async complete callback data is null"); + napi_value result = nullptr; + napi_get_undefined(env, &result); + + auto asyncContext = static_cast(data); + if ((status != napi_ok) && (asyncContext->status_ == napi_ok)) { + asyncContext->status_ = status; + NapiAsync::CommonCallbackRoutine(asyncContext, result); + return; + } + + if (asyncContext->processWork == nullptr) { + INTELL_VOICE_LOG_ERROR("process work is nullptr"); + NapiAsync::CommonCallbackRoutine(asyncContext, result); + return; + } + + auto cb = reinterpret_cast(asyncContext->engineNapi_)->callbackNapi_; + if (cb == nullptr) { + INTELL_VOICE_LOG_ERROR("get callback napi faild"); + NapiAsync::CommonCallbackRoutine(asyncContext, result); + return; + } + + cb->QueueAsyncWork(asyncContext); + if (asyncContext->processWork(asyncContext) != 0) { + INTELL_VOICE_LOG_ERROR("process work failed"); + cb->ClearAsyncWork(true, "the request was aborted because intelligent voice processWork error"); + } +} +} // namespace IntellVoiceNapi +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/enroll_intell_voice_engine_napi.h b/frameworks/js/napi/enroll_intell_voice_engine_napi.h new file mode 100755 index 0000000..fe754c7 --- /dev/null +++ b/frameworks/js/napi/enroll_intell_voice_engine_napi.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 + * + * 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. + */ + +#ifndef ENROLL_INTELL_VOICE_ENGINE_NAPI_H +#define ENROLL_INTELL_VOICE_ENGINE_NAPI_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "enroll_intell_voice_engine.h" +#include "enroll_intell_voice_engine_callback_napi.h" + +#define ENROLL_ENGINE_NAPI_CLASS_NAME "EnrollIntelligentVoiceEngine" + +namespace OHOS { +namespace IntellVoiceNapi { +using OHOS::IntellVoice::EnrollIntellVoiceEngine; +using OHOS::IntellVoice::EngineConfig; + +class EnrollIntellVoiceEngineNapi { +public: + EnrollIntellVoiceEngineNapi(); + ~EnrollIntellVoiceEngineNapi(); + + static napi_value Constructor(napi_env env); + +private: + static napi_value New(napi_env env, napi_callback_info info); + + static napi_value GetSupportedRegions(napi_env env, napi_callback_info info); + static napi_value Init(napi_env env, napi_callback_info info); + static napi_value Start(napi_env env, napi_callback_info info); + static napi_value Stop(napi_env env, napi_callback_info info); + static napi_value Commit(napi_env env, napi_callback_info info); + static napi_value SetSensibility(napi_env env, napi_callback_info info); + static napi_value SetWakeupHapInfo(napi_env env, napi_callback_info info); + static napi_value SetParameter(napi_env env, napi_callback_info info); + static napi_value GetParameter(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + + static void CompleteCallback(napi_env env, napi_status status, void *data); + + std::shared_ptr engine_ = nullptr; + std::shared_ptr callbackNapi_ = nullptr; + EngineConfig config_; + bool isLast_ = false; + +private: + napi_env env_ = nullptr; + napi_ref wrapper_ = nullptr; +}; +} // namespace IntellVoiceNapi +} // namespace OHOS + +#endif diff --git a/frameworks/js/napi/intell_voice_manager_napi.cpp b/frameworks/js/napi/intell_voice_manager_napi.cpp new file mode 100755 index 0000000..a7dabe9 --- /dev/null +++ b/frameworks/js/napi/intell_voice_manager_napi.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 + * + * 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. + */ +#include "intell_voice_manager_napi.h" +#include "intell_voice_log.h" +#include "intell_voice_napi_queue.h" +#include "intell_voice_napi_util.h" +#include "enroll_intell_voice_engine_napi.h" +#include "wakeup_intell_voice_engine_napi.h" +#include "intell_voice_info.h" + +#define LOG_TAG "IntellVoiceManagerNapi" + +using namespace std; +using namespace OHOS::IntellVoice; + +namespace OHOS { +namespace IntellVoiceNapi { +static const std::string INTELLIGENT_VOICE_MANAGER_NAPI_CLASS_NAME = "IntelligentVoiceManager"; + +static __thread napi_ref g_managerConstructor = nullptr; +napi_ref IntellVoiceManagerNapi::serviceChangeTypeRef_ = nullptr; +napi_ref IntellVoiceManagerNapi::engineTypeRef_ = nullptr; +napi_ref IntellVoiceManagerNapi::sensibilityTypeRef_ = nullptr; +napi_ref IntellVoiceManagerNapi::enrollEventTypeRef_ = nullptr; +napi_ref IntellVoiceManagerNapi::wakeupEventTypeRef_ = nullptr; +napi_ref IntellVoiceManagerNapi::errorCodeRef_ = nullptr; + +static const std::map SERVICE_CHANGE_TYPE_MAP = { + {"SERVICE_UNAVAILABLE", SERVICE_UNAVAILABLE}, +}; + +static const std::map ENGINE_TYPE_MAP = { + {"ENROLL_ENGINE_TYPE", ENROLL_ENGINE_TYPE}, + {"WAKEUP_ENGINE_TYPE", WAKEUP_ENGINE_TYPE}, + {"UPDATE_ENGINE_TYPE", UPDATE_ENGINE_TYPE}, +}; + +static const std::map SENSIBILITY_TYPE_MAP = { + {"LOW_SENSIBILITY", LOW_SENSIBILITY}, + {"MIDDLE_SENSIBILITY", MIDDLE_SENSIBILITY}, + {"HIGH_SENSIBILITY", HIGH_SENSIBILITY}, +}; + +static const std::map ENROLL_EVENT_TYPE_MAP = { + {"INTELLIGENT_VOICE_EVENT_ENROLL_NONE", INTELLIGENT_VOICE_EVENT_ENROLL_NONE}, + {"INTELLIGENT_VOICE_EVENT_ENROLL_INIT_DONE", INTELLIGENT_VOICE_EVENT_ENROLL_INIT_DONE}, + {"INTELLIGENT_VOICE_EVENT_ENROLL_COMPLETE", INTELLIGENT_VOICE_EVENT_ENROLL_COMPLETE}, + {"INTELLIGENT_VOICE_EVENT_COMMIT_ENROLL_COMPLETE", INTELLIGENT_VOICE_EVENT_COMMIT_ENROLL_COMPLETE}, +}; + +static const std::map WAKEUP_EVENT_TYPE_MAP = { + {"INTELLIGENT_VOICE_EVENT_WAKEUP_NONE", INTELLIGENT_VOICE_EVENT_WAKEUP_NONE}, + {"INTELLIGENT_VOICE_EVENT_RECOGNIZE_COMPLETE", INTELLIGENT_VOICE_EVENT_RECOGNIZE_COMPLETE}, +}; + +static const std::map ERROR_CODE_MAP = { + {"INTELLIGENT_VOICE_SUCCESS", INTELLIGENT_VOICE_SUCCESS}, + {"INTELLIGENT_VOICE_NO_MEMORY", INTELLIGENT_VOICE_NO_MEMORY}, + {"INTELLIGENT_VOICE_INVALID_PARAM", INTELLIGENT_VOICE_INVALID_PARAM}, + {"INTELLIGENT_VOICE_INIT_FAILED", INTELLIGENT_VOICE_INIT_FAILED}, + {"INTELLIGENT_VOICE_ENROLL_FAILED", INTELLIGENT_VOICE_ENROLL_FAILED}, + {"INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED", INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED}, + {"INTELLIGENT_VOICE_RECOGNIZE_FAILED", INTELLIGENT_VOICE_RECOGNIZE_FAILED}, +}; + +IntellVoiceManagerNapi::IntellVoiceManagerNapi() +{ + INTELL_VOICE_LOG_INFO("enter"); +} + +IntellVoiceManagerNapi::~IntellVoiceManagerNapi() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (wrapper_ != nullptr) { + napi_delete_reference(env_, wrapper_); + } +} + +void IntellVoiceManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (nativeObject != nullptr) { + auto obj = static_cast(nativeObject); + delete obj; + } +} + +napi_value IntellVoiceManagerNapi::Constructor(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_status status; + size_t argCount = 0; + napi_value jsThis = nullptr; + napi_value undefinedResult = nullptr; + napi_get_undefined(env, &undefinedResult); + + status = napi_get_cb_info(env, info, &argCount, nullptr, &jsThis, nullptr); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("invalid number of arguments"); + return undefinedResult; + } + + unique_ptr managerNapi = make_unique(); + if (managerNapi == nullptr) { + INTELL_VOICE_LOG_ERROR("no memory."); + return undefinedResult; + } + managerNapi->env_ = env; + managerNapi->manager_ = IntellVoiceManager::GetInstance(); + if (managerNapi->manager_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create native manager faild."); + return undefinedResult; + } + + status = napi_wrap(env, + jsThis, + static_cast(managerNapi.get()), + IntellVoiceManagerNapi::Destructor, + nullptr, + &(managerNapi->wrapper_)); + if (status == napi_ok) { + managerNapi.release(); + return jsThis; + } + + INTELL_VOICE_LOG_ERROR("failed to construct intell voice manager napi"); + return undefinedResult; +} + +napi_value IntellVoiceManagerNapi::Export(napi_env env, napi_value exports) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_status status; + napi_value constructor; + napi_value result = nullptr; + const int32_t refCount = 1; + napi_get_undefined(env, &result); + + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getCapabilityInfo", GetCapabilityInfo), + DECLARE_NAPI_FUNCTION("on", On), + DECLARE_NAPI_FUNCTION("off", Off), + }; + + napi_property_descriptor staticProperties[] = { + DECLARE_NAPI_STATIC_FUNCTION("getIntelligentVoiceManager", GetIntelligentVoiceManager), + DECLARE_NAPI_PROPERTY("ServiceChangeType", CreatePropertyBase(env, SERVICE_CHANGE_TYPE_MAP, + serviceChangeTypeRef_)), + DECLARE_NAPI_PROPERTY("IntelligentVoiceEngineType", CreatePropertyBase(env, ENGINE_TYPE_MAP, + engineTypeRef_)), + DECLARE_NAPI_PROPERTY("SensibilityType", CreatePropertyBase(env, SENSIBILITY_TYPE_MAP, + sensibilityTypeRef_)), + DECLARE_NAPI_PROPERTY("EnrollIntelligentVoiceEventType", CreatePropertyBase(env, ENROLL_EVENT_TYPE_MAP, + enrollEventTypeRef_)), + DECLARE_NAPI_PROPERTY("WakeupIntelligentVoiceEventType", CreatePropertyBase(env, WAKEUP_EVENT_TYPE_MAP, + wakeupEventTypeRef_)), + DECLARE_NAPI_PROPERTY("IntelligentVoiceErrorCode", CreatePropertyBase(env, ERROR_CODE_MAP, errorCodeRef_)), + }; + + status = napi_define_class(env, + INTELLIGENT_VOICE_MANAGER_NAPI_CLASS_NAME.c_str(), + NAPI_AUTO_LENGTH, + Constructor, + nullptr, + sizeof(properties) / sizeof(properties[0]), + properties, + &constructor); + if (status != napi_ok) { + return result; + } + + status = napi_create_reference(env, constructor, refCount, &g_managerConstructor); + if (status == napi_ok) { + status = napi_set_named_property(env, exports, INTELLIGENT_VOICE_MANAGER_NAPI_CLASS_NAME.c_str(), constructor); + if (status == napi_ok) { + status = napi_define_properties( + env, exports, sizeof(staticProperties) / sizeof(staticProperties[0]), staticProperties); + if (status == napi_ok) { + return exports; + } + } + } + + INTELL_VOICE_LOG_ERROR("failed to export intelligent voice manager napi"); + return result; +} + +napi_value IntellVoiceManagerNapi::GetCapabilityInfo(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value result = nullptr; + napi_create_array(env, &result); + napi_set_element(env, result, 0, SetValue(env, ENROLL_ENGINE_TYPE)); + napi_set_element(env, result, 1, SetValue(env, WAKEUP_ENGINE_TYPE)); + return result; +} + +napi_value IntellVoiceManagerNapi::On(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + return nullptr; +} + +napi_value IntellVoiceManagerNapi::Off(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + return nullptr; +} + +napi_value IntellVoiceManagerNapi::GetIntelligentVoiceManager(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + + napi_status status; + size_t argCount = 0; + + status = napi_get_cb_info(env, info, &argCount, nullptr, nullptr, nullptr); + if (status != napi_ok || argCount != 0) { + INTELL_VOICE_LOG_ERROR("Invalid arguments"); + return nullptr; + } + + return IntellVoiceManagerNapi::GetIntelligentVoiceManagerWrapper(env); +} + +napi_value IntellVoiceManagerNapi::GetIntelligentVoiceManagerWrapper(napi_env env) +{ + napi_status status; + napi_value result = nullptr; + napi_value constructor; + + status = napi_get_reference_value(env, g_managerConstructor, &constructor); + if (status == napi_ok) { + status = napi_new_instance(env, constructor, 0, nullptr, &result); + if (status == napi_ok) { + return result; + } + } + INTELL_VOICE_LOG_ERROR("failed to get intell voice manager wrapper"); + napi_get_undefined(env, &result); + + return result; +} + +napi_value IntellVoiceManagerNapi::CreateEnrollIntelligentVoiceEngine(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class CreateContext : public AsyncContext { + public: + napi_value object = nullptr; + napi_ref ref = nullptr; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create CreateContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = + napi_new_instance(env, EnrollIntellVoiceEngineNapi::Constructor(env), argc, argv, &(context->object)); + CHECK_STATUS_RETURN_VOID(context, "new napi instance failed"); + context->status_ = napi_create_reference(env, context->object, 1, &(context->ref)); + CHECK_STATUS_RETURN_VOID(context, "create ref failed"); + }; + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + auto createContext = static_cast(context); + napi_get_reference_value(createContext->env_, createContext->ref, &result); + }; + + return NapiAsync::AsyncWork(context, "CreateEnrollIntelligentVoiceEngine", execute, complete); +} + +napi_value IntellVoiceManagerNapi::CreateWakeupIntelligentVoiceEngine(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class CreateContext : public AsyncContext { + public: + napi_value object = nullptr; + napi_ref ref = nullptr; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create CreateContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = + napi_new_instance(env, WakeupIntellVoiceEngineNapi::Constructor(env), argc, argv, &(context->object)); + CHECK_STATUS_RETURN_VOID(context, "new napi instance failed"); + context->status_ = napi_create_reference(env, context->object, 1, &(context->ref)); + CHECK_STATUS_RETURN_VOID(context, "create ref failed"); + }; + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + auto createContext = static_cast(context); + napi_get_reference_value(createContext->env_, createContext->ref, &result); + }; + + return NapiAsync::AsyncWork(context, "CreateWakeupIntelligentVoiceEngine", execute, complete); +} + +template napi_value IntellVoiceManagerNapi::CreatePropertyBase(napi_env env, T &propertyMap, napi_ref ref) +{ + napi_value result = nullptr; + napi_status status; + string propName; + int32_t enumValue; + napi_value enumNapiValue; + + status = napi_create_object(env, &result); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to create object"); + napi_get_undefined(env, &result); + return result; + } + + for (auto &iter : propertyMap) { + propName = iter.first; + enumValue = iter.second; + + enumNapiValue = SetValue(env, enumValue); + status = napi_set_named_property(env, result, propName.c_str(), enumNapiValue); + if (status != napi_ok) { + break; + } + propName.clear(); + } + + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to set base property"); + napi_get_undefined(env, &result); + return result; + } + + status = napi_create_reference(env, result, 1, &ref); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to create base property"); + napi_get_undefined(env, &result); + return result; + } + + INTELL_VOICE_LOG_INFO("create base property success"); + return result; +} + +EXTERN_C_START +static napi_value Export(napi_env env, napi_value exports) +{ + // Export static methods and enum + napi_status status; + napi_property_descriptor staticProperties[] = { + DECLARE_NAPI_STATIC_FUNCTION( + "createEnrollIntelligentVoiceEngine", IntellVoiceManagerNapi::CreateEnrollIntelligentVoiceEngine), + DECLARE_NAPI_STATIC_FUNCTION( + "createWakeupIntelligentVoiceEngine", IntellVoiceManagerNapi::CreateWakeupIntelligentVoiceEngine), + }; + status = + napi_define_properties(env, exports, sizeof(staticProperties) / sizeof(staticProperties[0]), staticProperties); + INTELL_VOICE_LOG_INFO("init static properties, status: %{public}d", status); + + // Export Class + IntellVoiceManagerNapi::Export(env, exports); + + status = napi_set_named_property( + env, exports, ENROLL_ENGINE_NAPI_CLASS_NAME, EnrollIntellVoiceEngineNapi::Constructor(env)); + INTELL_VOICE_LOG_INFO("init %{public}s, status: %{public}d", ENROLL_ENGINE_NAPI_CLASS_NAME, status); + + status = napi_set_named_property( + env, exports, WAKEUP_ENGINE_NAPI_CLASS_NAME, WakeupIntellVoiceEngineNapi::Constructor(env)); + INTELL_VOICE_LOG_INFO("init %{public}s, status: %{public}d", WAKEUP_ENGINE_NAPI_CLASS_NAME, status); + + return exports; +} +EXTERN_C_END + +static napi_module g_module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Export, + .nm_modname = "ai.intelligentVoice", + .nm_priv = ((void *)0), + .reserved = {0}, +}; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&g_module); +} +} // namespace IntellVoiceNapi +} // namespace OHOS diff --git a/frameworks/js/napi/intell_voice_manager_napi.h b/frameworks/js/napi/intell_voice_manager_napi.h new file mode 100755 index 0000000..910801f --- /dev/null +++ b/frameworks/js/napi/intell_voice_manager_napi.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 + * + * 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. + */ + +#ifndef INTELL_VOICE_MANAGER_NAPI_H +#define INTELL_VOICE_MANAGER_NAPI_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +#include "intell_voice_manager.h" + +namespace OHOS { +namespace IntellVoiceNapi { +using OHOS::IntellVoice::IntellVoiceManager; + +class IntellVoiceManagerNapi { +public: + IntellVoiceManagerNapi(); + ~IntellVoiceManagerNapi(); + + static napi_value Export(napi_env env, napi_value exports); + static napi_value CreateEnrollIntelligentVoiceEngine(napi_env env, napi_callback_info info); + static napi_value CreateWakeupIntelligentVoiceEngine(napi_env env, napi_callback_info info); + +private: + static void Destructor(napi_env env, void *nativeObject, void *finalize_hint); + static napi_value Constructor(napi_env env, napi_callback_info info); + + static napi_value GetCapabilityInfo(napi_env env, napi_callback_info info); + static napi_value On(napi_env env, napi_callback_info info); + static napi_value Off(napi_env env, napi_callback_info info); + + static napi_value GetIntelligentVoiceManager(napi_env env, napi_callback_info info); + static napi_value GetIntelligentVoiceManagerWrapper(napi_env env); + template static napi_value CreatePropertyBase(napi_env env, T &propertyMap, napi_ref ref); + + napi_env env_ = nullptr; + napi_ref wrapper_ = nullptr; + IntellVoiceManager *manager_ = nullptr; + static napi_ref serviceChangeTypeRef_; + static napi_ref engineTypeRef_; + static napi_ref sensibilityTypeRef_; + static napi_ref enrollEventTypeRef_; + static napi_ref wakeupEventTypeRef_; + static napi_ref errorCodeRef_; +}; +} // namespace IntellVoiceNapi +} // namespace OHOS +#endif diff --git a/frameworks/js/napi/intell_voice_napi_queue.cpp b/frameworks/js/napi/intell_voice_napi_queue.cpp new file mode 100755 index 0000000..03bf8a7 --- /dev/null +++ b/frameworks/js/napi/intell_voice_napi_queue.cpp @@ -0,0 +1,193 @@ +/* + * 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. + */ + +#include "intell_voice_napi_queue.h" +#include "intell_voice_napi_util.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceNapiQueue" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceNapi { +AsyncComplete NapiAsync::complete_ = nullptr; + +AsyncContext::AsyncContext() +{ + INTELL_VOICE_LOG_INFO("enter"); +} +AsyncContext::~AsyncContext() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (env_ != nullptr) { + if (work_ != nullptr) { + napi_delete_async_work(env_, work_); + } + if (callbackRef_ != nullptr) { + napi_delete_reference(env_, callbackRef_); + } + env_ = nullptr; + } +} + +void AsyncContext::GetCbInfo(napi_env env, napi_callback_info info, size_t callBackIndex, CbInfoParser parser) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value jsThis = nullptr; + const int32_t refCount = 1; + size_t argc = ARGC_MAX; + napi_value args[ARGC_MAX] = {nullptr}; + + env_ = env; + status_ = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); + CHECK_STATUS_RETURN_VOID(this, "Failed to get cb info"); + + status_ = napi_unwrap(env, jsThis, &engineNapi_); + CHECK_STATUS_RETURN_VOID(this, "Failed to get engine napi instance"); + + if (argc > callBackIndex) { + napi_valuetype valueType = napi_undefined; + napi_typeof(env, args[callBackIndex], &valueType); + if (valueType == napi_function) { + status_ = napi_create_reference(env, args[callBackIndex], refCount, &callbackRef_); + CHECK_STATUS_RETURN_VOID(this, "Failed to create callback reference"); + } else { + INTELL_VOICE_LOG_ERROR("Failed to get asyncCallback, type mismatch"); + } + } + + if (parser) { + parser(argc, args); + } +} + +napi_value NapiAsync::AsyncWork( + shared_ptr context, const string &name, AsyncExecute execute, AsyncComplete complete) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value result = nullptr; + if (context->callbackRef_ == nullptr) { + napi_create_promise(context->env_, &context->deferred_, &result); + } else { + napi_get_undefined(context->env_, &result); + } + + napi_value resource = nullptr; + complete_ = complete; + napi_create_string_utf8(context->env_, name.c_str(), NAPI_AUTO_LENGTH, &resource); + napi_create_async_work(context->env_, + nullptr, + resource, + execute, + AsyncCompleteCallback, + static_cast(context.get()), + &context->work_); + + napi_queue_async_work(context->env_, context->work_); + context->contextSp_ = context; + + return result; +} + +napi_value NapiAsync::AsyncWork( + shared_ptr context, const string &name, AsyncExecute execute, napi_async_complete_callback complete) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value result = nullptr; + if (context->callbackRef_ == nullptr) { + napi_create_promise(context->env_, &context->deferred_, &result); + } else { + napi_get_undefined(context->env_, &result); + } + + napi_value resource = nullptr; + napi_create_string_utf8(context->env_, name.c_str(), NAPI_AUTO_LENGTH, &resource); + napi_create_async_work( + context->env_, nullptr, resource, execute, complete, static_cast(context.get()), &context->work_); + + napi_queue_async_work(context->env_, context->work_); + context->contextSp_ = context; + + return result; +} + +void NapiAsync::CommonCallbackRoutine(AsyncContext *context, const napi_value &data) +{ + CHECK_RETURN_VOID(context != nullptr, "async context is null"); + + if (context->deferred_) { + HandlePromise(context, data); + } else { + HandleAsyncCallback(context, data); + } + context->contextSp_.reset(); +} + +void NapiAsync::HandlePromise(AsyncContext *context, const napi_value &data) +{ + napi_value result = nullptr; + napi_value error = nullptr; + napi_get_undefined(context->env_, &result); + napi_get_undefined(context->env_, &error); + + if (context->status_ == napi_ok) { + result = data; + napi_resolve_deferred(context->env_, context->deferred_, result); + return; + } + napi_value message = nullptr; + napi_create_string_utf8(context->env_, context->error_.c_str(), NAPI_AUTO_LENGTH, &message); + napi_create_error(context->env_, nullptr, message, &error); + napi_reject_deferred(context->env_, context->deferred_, error); +} + +void NapiAsync::HandleAsyncCallback(AsyncContext *context, const napi_value &data) +{ + const size_t argc = 2; + napi_value args[argc] = {nullptr, nullptr}; + napi_value callback = nullptr; + napi_value ret = nullptr; + if (context->status_ == napi_ok) { + napi_get_undefined(context->env_, &args[0]); + args[1] = data; + } else { + napi_value message = nullptr; + napi_create_string_utf8(context->env_, context->error_.c_str(), NAPI_AUTO_LENGTH, &message); + napi_create_error(context->env_, nullptr, message, &args[0]); + napi_get_undefined(context->env_, &args[1]); + } + napi_get_reference_value(context->env_, context->callbackRef_, &callback); + napi_call_function(context->env_, nullptr, callback, argc, args, &ret); +} + +void NapiAsync::AsyncCompleteCallback(napi_env env, napi_status status, void *data) +{ + INTELL_VOICE_LOG_INFO("enter"); + CHECK_RETURN_VOID(data != nullptr, "async complete callback data is null"); + napi_value result = nullptr; + napi_get_undefined(env, &result); + auto context = static_cast(data); + if ((status != napi_ok) && (context->status_ == napi_ok)) { + context->status_ = status; + } + + if (context->status_ == napi_ok && (complete_ != nullptr)) { + complete_(context, result); + } + CommonCallbackRoutine(context, result); +} +} // namespace IntellVoiceNapi +} // namespace OHOS diff --git a/frameworks/js/napi/intell_voice_napi_queue.h b/frameworks/js/napi/intell_voice_napi_queue.h new file mode 100755 index 0000000..f6d07d9 --- /dev/null +++ b/frameworks/js/napi/intell_voice_napi_queue.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#ifndef INTELL_VOICE_NAPI_QUEUE_H +#define INTELL_VOICE_NAPI_QUEUE_H + +#include +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace IntellVoiceNapi { +constexpr size_t ARGC_MAX = 4; + +using CbInfoParser = std::function; + +#define CHECK_STATUS_RETURN_VOID(context, message) \ + do { \ + if ((context)->status_ != napi_ok) { \ + (context)->error_ = std::string(message); \ + INTELL_VOICE_LOG_ERROR(message); \ + return; \ + } \ + } while (0) + +class AsyncContext { +public: + AsyncContext(); + ~AsyncContext(); + void GetCbInfo(napi_env env, napi_callback_info info, size_t callBackIndex, CbInfoParser parser); + + napi_env env_ = nullptr; + void *engineNapi_ = nullptr; + + napi_status status_ = napi_invalid_arg; + std::string error_; + int32_t result_ = -1; + +private: + napi_async_work work_ = nullptr; + napi_deferred deferred_ = nullptr; + napi_ref callbackRef_ = nullptr; + std::shared_ptr contextSp_ = nullptr; + + friend class NapiAsync; +}; + +using AsyncExecute = napi_async_execute_callback; +using AsyncComplete = std::function; + +class NapiAsync { +public: + static napi_value AsyncWork(std::shared_ptr context, const std::string &name, AsyncExecute execute, + AsyncComplete complete = nullptr); + static napi_value AsyncWork(std::shared_ptr context, const std::string &name, AsyncExecute execute, + napi_async_complete_callback complete); + static void CommonCallbackRoutine(AsyncContext *context, const napi_value &data); + +private: + static void AsyncCompleteCallback(napi_env env, napi_status status, void *data); + static void HandlePromise(AsyncContext *context, const napi_value &data); + static void HandleAsyncCallback(AsyncContext *context, const napi_value &data); + + static AsyncComplete complete_; +}; +} // namespace IntellVoiceNapi +} // namespace OHOS + +#endif diff --git a/frameworks/js/napi/intell_voice_napi_util.cpp b/frameworks/js/napi/intell_voice_napi_util.cpp new file mode 100755 index 0000000..f509bc2 --- /dev/null +++ b/frameworks/js/napi/intell_voice_napi_util.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 + * + * 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. + */ + +#include "intell_voice_napi_util.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceNapiUtil" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceNapi { +static const int32_t MAX_STRING_BUFFSIZE = 1024; + +IntellVoiceRef::IntellVoiceRef(napi_env env, napi_value value) +{ + INTELL_VOICE_LOG_INFO("enter"); + env_ = env; + napi_create_reference(env_, value, 1, &ref_); +} + +IntellVoiceRef::~IntellVoiceRef() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (env_ != nullptr && ref_ != nullptr) { + napi_delete_reference(env_, ref_); + } + env_ = nullptr; + ref_ = nullptr; +} + +napi_value IntellVoiceRef::GetRefValue() +{ + napi_value value = nullptr; + napi_status status = napi_get_reference_value(env_, ref_, &value); + if (status != napi_ok || value == nullptr) { + INTELL_VOICE_LOG_ERROR("get reference value fail"); + return nullptr; + } + return value; +} + +napi_value SetValue(napi_env env, const int32_t &value) +{ + napi_value result = nullptr; + napi_status status = napi_create_int32(env, value, &result); + if (status != napi_ok || result == nullptr) { + INTELL_VOICE_LOG_ERROR("get js value fail"); + return nullptr; + } + return result; +} + +napi_value SetValue(napi_env env, const string &value) +{ + napi_value result = nullptr; + napi_status status = napi_create_string_utf8(env, value.c_str(), value.size(), &result); + if (status != napi_ok || result == nullptr) { + INTELL_VOICE_LOG_ERROR("get js value fail"); + return nullptr; + } + return result; +} + +napi_status GetValue(napi_env env, napi_value jsValue, int32_t &value) +{ + napi_valuetype valueType = napi_undefined; + napi_typeof(env, jsValue, &valueType); + if (valueType != napi_number) { + return napi_generic_failure; + } + return napi_get_value_int32(env, jsValue, &value); +} + +napi_status GetValue(napi_env env, napi_value jsValue, bool &value) +{ + napi_valuetype valueType = napi_undefined; + napi_typeof(env, jsValue, &valueType); + if (valueType != napi_boolean) { + return napi_generic_failure; + } + return napi_get_value_bool(env, jsValue, &value); +} + +napi_status GetValue(napi_env env, napi_value jsValue, string &value) +{ + size_t bufferSize = 0; + napi_valuetype valueType = napi_undefined; + napi_typeof(env, jsValue, &valueType); + if (valueType != napi_string) { + return napi_generic_failure; + } + napi_status status = napi_get_value_string_utf8(env, jsValue, nullptr, 0, &bufferSize); + if (status != napi_ok || bufferSize == 0 || bufferSize >= MAX_STRING_BUFFSIZE) { + INTELL_VOICE_LOG_ERROR("failed to get buffersize"); + return napi_generic_failure; + } + + char *buffer = (char *)malloc((bufferSize + 1) * sizeof(char)); + if (buffer == nullptr) { + INTELL_VOICE_LOG_ERROR("no memory"); + return napi_generic_failure; + } + + status = napi_get_value_string_utf8(env, jsValue, buffer, bufferSize + 1, &bufferSize); + value = buffer; + free(buffer); + buffer = nullptr; + return status; +} +} // namespace IntellVoiceNapi +} // namespace OHOS diff --git a/frameworks/js/napi/intell_voice_napi_util.h b/frameworks/js/napi/intell_voice_napi_util.h new file mode 100755 index 0000000..2076ac4 --- /dev/null +++ b/frameworks/js/napi/intell_voice_napi_util.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 + * + * 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. + */ + +#ifndef INTELL_VOICE_NAPI_UTIL_H +#define INTELL_VOICE_NAPI_UTIL_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +namespace OHOS { +namespace IntellVoiceNapi { +#define CHECK_RETURN_VOID(condition, message) \ + do { \ + if (!(condition)) { \ + INTELL_VOICE_LOG_ERROR(message); \ + return; \ + } \ + } while (0) + +class IntellVoiceRef { +public: + IntellVoiceRef(napi_env env, napi_value value); + ~IntellVoiceRef(); + napi_value GetRefValue(); + +private: + napi_env env_ = nullptr; + napi_ref ref_ = nullptr; +}; + +napi_value SetValue(napi_env env, const int32_t &value); +napi_value SetValue(napi_env env, const std::string &value); + +napi_status GetValue(napi_env env, napi_value jsValue, int32_t &value); +napi_status GetValue(napi_env env, napi_value jsValue, bool &value); +napi_status GetValue(napi_env env, napi_value jsValue, std::string &value); +} // namespace IntellVoiceNapi +} // namespace OHOS +#endif diff --git a/frameworks/js/napi/wakeup_intell_voice_engine_napi.cpp b/frameworks/js/napi/wakeup_intell_voice_engine_napi.cpp new file mode 100755 index 0000000..2365c82 --- /dev/null +++ b/frameworks/js/napi/wakeup_intell_voice_engine_napi.cpp @@ -0,0 +1,444 @@ +/* + * 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. + */ + +#include "wakeup_intell_voice_engine_napi.h" + +#include "want.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +#include "intell_voice_napi_util.h" +#include "intell_voice_napi_queue.h" + +#include "intell_voice_log.h" +#include "i_intell_voice_engine_callback.h" + +#define LOG_TAG "WakeupIntellVoiceEngineNapi" + +using namespace std; +using namespace OHOS::IntellVoice; + +namespace OHOS { +namespace IntellVoiceNapi { +static const std::string INTELL_VOICE_EVENT_CALLBACK_NAME = "IntellVoiceEvent"; + +WakeupIntellVoiceEngineNapi::WakeupIntellVoiceEngineNapi() +{ + INTELL_VOICE_LOG_INFO("enter, %{public}p", this); +} + +WakeupIntellVoiceEngineNapi::~WakeupIntellVoiceEngineNapi() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (wrapper_ != nullptr) { + napi_delete_reference(env_, wrapper_); + } +} + +napi_value WakeupIntellVoiceEngineNapi::New(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t argc = 1; + napi_value args[1] = {nullptr}; + + napi_value jsThis = nullptr; + napi_value undefinedResult = nullptr; + napi_get_undefined(env, &undefinedResult); + + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr)); + + unique_ptr engineNapi = make_unique(); + if (engineNapi == nullptr) { + INTELL_VOICE_LOG_ERROR("Failed to create WakeupIntellVoiceEngineNapi, No memory."); + return undefinedResult; + } + engineNapi->env_ = env; + + WakeupIntelligentVoiceEngineDescriptor descriptor = {}; + napi_value value = nullptr; + if (napi_get_named_property(env, args[0], "needApAlgEngine", &value) == napi_ok) { + GetValue(env, value, descriptor.needApAlgEngine); + } + if (napi_get_named_property(env, args[0], "wakeupPhrase", &value) == napi_ok) { + GetValue(env, value, descriptor.wakeupPhrase); + } + INTELL_VOICE_LOG_INFO("EngineDescriptor needApAlgEngine: %{public}d", descriptor.needApAlgEngine); + INTELL_VOICE_LOG_INFO("EngineDescriptor wakeupPhrase: %{public}s", descriptor.wakeupPhrase.c_str()); + + engineNapi->engine_ = std::make_shared(descriptor); + if (engineNapi->engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create intell voice engine faild."); + return undefinedResult; + } + + auto finalize = [](napi_env env, void *data, void *hint) { + INTELL_VOICE_LOG_INFO("WakeupIntellVoiceEngineNapi finalize callback"); + if (data != nullptr) { + auto obj = static_cast(data); + delete obj; + } + }; + + NAPI_CALL(env, + napi_wrap(env, jsThis, static_cast(engineNapi.get()), finalize, nullptr, &(engineNapi->wrapper_))); + engineNapi.release(); + return jsThis; +} + +napi_value WakeupIntellVoiceEngineNapi::Constructor(napi_env env) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_status status; + napi_value constructor; + napi_get_undefined(env, &constructor); + + napi_property_descriptor properties[] = { + DECLARE_NAPI_FUNCTION("getSupportedRegions", GetSupportedRegions), + DECLARE_NAPI_FUNCTION("setSensibility", SetSensibility), + DECLARE_NAPI_FUNCTION("setWakeupHapInfo", SetWakeupHapInfo), + DECLARE_NAPI_FUNCTION("setParameter", SetParameter), + DECLARE_NAPI_FUNCTION("getParameter", GetParameter), + DECLARE_NAPI_FUNCTION("release", Release), + DECLARE_NAPI_FUNCTION("on", On), + DECLARE_NAPI_FUNCTION("off", Off), + }; + + status = napi_define_class(env, + WAKEUP_ENGINE_NAPI_CLASS_NAME, + NAPI_AUTO_LENGTH, + New, + nullptr, + sizeof(properties) / sizeof(properties[0]), + properties, + &constructor); + + return constructor; +} + +napi_value WakeupIntellVoiceEngineNapi::GetSupportedRegions(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("get supported regions complete"); + napi_create_array(context->env_, &result); + napi_set_element(context->env_, result, 0, SetValue(context->env_, "CN")); + }; + + return NapiAsync::AsyncWork(context, "GetSupportedRegions", execute, complete); +} + +napi_value WakeupIntellVoiceEngineNapi::SetParameter(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 2; + class SetParameterContext : public AsyncContext { + public: + string key; + string value; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetParameterContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = GetValue(env, argv[0], context->key); + CHECK_STATUS_RETURN_VOID(context, "Failed to get key"); + context->status_ = GetValue(env, argv[1], context->value); + CHECK_STATUS_RETURN_VOID(context, "Failed to get value"); + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetParameter(asyncContext->key, asyncContext->value); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetParameter", execute); +} + +napi_value WakeupIntellVoiceEngineNapi::GetParameter(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + asyncContext->status_ = napi_ok; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("get parameter complete"); + result = SetValue(context->env_, "value"); + }; + return NapiAsync::AsyncWork(context, "GetParameter", execute, complete); +} + +napi_value WakeupIntellVoiceEngineNapi::SetSensibility(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class SetSensibilityContext : public AsyncContext { + public: + int32_t sensibility; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetSensibilityContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + context->status_ = GetValue(env, argv[0], context->sensibility); + CHECK_STATUS_RETURN_VOID(context, "Failed to get sensibility"); + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetSensibility(asyncContext->sensibility); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetSensibility", execute); +} + +napi_value WakeupIntellVoiceEngineNapi::SetWakeupHapInfo(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 1; + class SetWakeupHapContext : public AsyncContext { + public: + WakeupHapInfo hapInfo; + }; + auto context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create SetWakeupHapContext faild, No memory"); + return nullptr; + } + + CbInfoParser parser = [env, context](size_t argc, napi_value *argv) { + napi_value temp = nullptr; + if (napi_get_named_property(env, argv[0], "bundleName", &temp) == napi_ok) { + GetValue(env, temp, context->hapInfo.bundleName); + } + if (napi_get_named_property(env, argv[0], "abilityName", &temp) == napi_ok) { + GetValue(env, temp, context->hapInfo.abilityName); + } + }; + + context->GetCbInfo(env, info, cbIndex, parser); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->SetWakeupHapInfo(asyncContext->hapInfo); + asyncContext->status_ = napi_ok; + }; + + return NapiAsync::AsyncWork(context, "SetWakeupHapInfo", execute); +} + +napi_value WakeupIntellVoiceEngineNapi::Release(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + size_t cbIndex = 0; + shared_ptr context = make_shared(); + if (context == nullptr) { + INTELL_VOICE_LOG_ERROR("create AsyncContext faild, No memory"); + return nullptr; + } + + context->GetCbInfo(env, info, cbIndex, nullptr); + + AsyncExecute execute = [](napi_env env, void *data) { + auto asyncContext = static_cast(data); + auto engine = reinterpret_cast(asyncContext->engineNapi_)->engine_; + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("get engine instance faild"); + return; + } + asyncContext->result_ = engine->Release(); + asyncContext->status_ = napi_ok; + reinterpret_cast(asyncContext->engineNapi_)->engine_ = nullptr; + }; + + AsyncComplete complete = [](AsyncContext *context, napi_value &result) { + INTELL_VOICE_LOG_INFO("release engine complete"); + }; + return NapiAsync::AsyncWork(context, "Release", execute, complete); +} + +napi_value WakeupIntellVoiceEngineNapi::On(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + + napi_value undefinedResult = nullptr; + napi_get_undefined(env, &undefinedResult); + + const size_t expectArgCount = 2; + size_t argCount = 2; + napi_value args[expectArgCount] = {0}; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr); + if (status != napi_ok || argCount != expectArgCount) { + INTELL_VOICE_LOG_ERROR("failed to get parameters"); + return undefinedResult; + } + + napi_valuetype eventType = napi_undefined; + if (napi_typeof(env, args[0], &eventType) != napi_ok || eventType != napi_string) { + INTELL_VOICE_LOG_ERROR("callback event name type mismatch"); + return undefinedResult; + } + + string callbackName = ""; + status = GetValue(env, args[0], callbackName); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to get callbackName"); + return undefinedResult; + } + INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str()); + + napi_valuetype handler = napi_undefined; + if (napi_typeof(env, args[1], &handler) != napi_ok || handler != napi_function) { + INTELL_VOICE_LOG_ERROR("callback handler type mismatch"); + return undefinedResult; + } + + return RegisterCallback(env, jsThis, args); +} + +napi_value WakeupIntellVoiceEngineNapi::RegisterCallback(napi_env env, napi_value jsThis, napi_value *args) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value result = nullptr; + napi_get_undefined(env, &result); + + WakeupIntellVoiceEngineNapi *engineNapi = nullptr; + napi_status status = napi_unwrap(env, jsThis, reinterpret_cast(&engineNapi)); + if (status != napi_ok || engineNapi == nullptr) { + INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance"); + return result; + } + + if (engineNapi->engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return result; + } + + engineNapi->callbackNapi_ = make_shared(env, args[1]); + engineNapi->engine_->SetCallback(engineNapi->callbackNapi_); + INTELL_VOICE_LOG_INFO("Set callback finish"); + return result; +} + +napi_value WakeupIntellVoiceEngineNapi::Off(napi_env env, napi_callback_info info) +{ + INTELL_VOICE_LOG_INFO("enter"); + + napi_value undefinedResult = nullptr; + napi_get_undefined(env, &undefinedResult); + + const size_t expectArgCount = 1; + size_t argCount = 1; + napi_value args[expectArgCount] = {0}; + napi_value jsThis = nullptr; + + napi_status status = napi_get_cb_info(env, info, &argCount, args, &jsThis, nullptr); + if (status != napi_ok || argCount != expectArgCount) { + INTELL_VOICE_LOG_ERROR("failed to get parameters"); + return undefinedResult; + } + + napi_valuetype eventType = napi_undefined; + if (napi_typeof(env, args[0], &eventType) != napi_ok || eventType != napi_string) { + INTELL_VOICE_LOG_ERROR("callback event name type mismatch"); + return undefinedResult; + } + + string callbackName = ""; + status = GetValue(env, args[0], callbackName); + if (status != napi_ok) { + INTELL_VOICE_LOG_ERROR("failed to get callbackName"); + return undefinedResult; + } + INTELL_VOICE_LOG_INFO("callbackName: %{public}s", callbackName.c_str()); + + return UnregisterCallback(env, jsThis, callbackName); +} + +napi_value WakeupIntellVoiceEngineNapi::UnregisterCallback(napi_env env, napi_value jsThis, const string &callbackName) +{ + INTELL_VOICE_LOG_INFO("enter"); + napi_value result = nullptr; + napi_get_undefined(env, &result); + + WakeupIntellVoiceEngineNapi *engineNapi = nullptr; + napi_status status = napi_unwrap(env, jsThis, reinterpret_cast(&engineNapi)); + if (status != napi_ok || engineNapi == nullptr) { + INTELL_VOICE_LOG_ERROR("Failed to get engine napi instance"); + return result; + } + + if (callbackName != INTELL_VOICE_EVENT_CALLBACK_NAME) { + INTELL_VOICE_LOG_ERROR("No such off callback supported"); + return result; + } + + return result; +} +} // namespace IntellVoiceNapi +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/js/napi/wakeup_intell_voice_engine_napi.h b/frameworks/js/napi/wakeup_intell_voice_engine_napi.h new file mode 100755 index 0000000..d207d56 --- /dev/null +++ b/frameworks/js/napi/wakeup_intell_voice_engine_napi.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 + * + * 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. + */ + +#ifndef WAKEUP_INTELL_VOICE_ENGINE_NAPI_H +#define WAKEUP_INTELL_VOICE_ENGINE_NAPI_H + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "engine_event_callback_napi.h" +#include "wakeup_intell_voice_engine.h" + +#define WAKEUP_ENGINE_NAPI_CLASS_NAME "WakeupIntelligentVoiceEngine" + +namespace OHOS { +namespace IntellVoiceNapi { +using OHOS::IntellVoice::WakeupIntellVoiceEngine; + +class WakeupIntellVoiceEngineNapi { +public: + WakeupIntellVoiceEngineNapi(); + ~WakeupIntellVoiceEngineNapi(); + + static napi_value Constructor(napi_env env); + + static napi_value GetSupportedRegions(napi_env env, napi_callback_info info); + static napi_value SetSensibility(napi_env env, napi_callback_info info); + static napi_value SetWakeupHapInfo(napi_env env, napi_callback_info info); + static napi_value SetParameter(napi_env env, napi_callback_info info); + static napi_value GetParameter(napi_env env, napi_callback_info info); + static napi_value Release(napi_env env, napi_callback_info info); + static napi_value On(napi_env env, napi_callback_info info); + static napi_value Off(napi_env env, napi_callback_info info); + + std::shared_ptr engine_ = nullptr; + std::shared_ptr callbackNapi_ = nullptr; + +private: + static napi_value New(napi_env env, napi_callback_info info); + + static napi_value RegisterCallback(napi_env env, napi_value jsThis, napi_value *args); + static napi_value UnregisterCallback(napi_env env, napi_value jsThis, const std::string &callbackName); + +private: + napi_env env_ = nullptr; + napi_ref wrapper_ = nullptr; +}; +} // namespace IntellVoiceNapi +} // namespace OHOS + +#endif diff --git a/frameworks/native/BUILD.gn b/frameworks/native/BUILD.gn new file mode 100755 index 0000000..d09c633 --- /dev/null +++ b/frameworks/native/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 +# +# 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("//build/ohos.gni") + +ohos_shared_library("intellvoice_native") { + sources = [ + "enroll_intell_voice_engine.cpp", + "intell_voice_manager.cpp", + "wakeup_intell_voice_engine.cpp", + ] + + include_dirs = [ + "//foundation/ai/intelligent_voice_framework/interfaces/inner_api/native", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine/proxy", + "//foundation/ai/intelligent_voice_framework/utils", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//foundation/ai/intelligent_voice_framework/services:intell_voice_proxy", + ] + + external_deps = [ + "ability_base:base", + "ability_base:want", + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} diff --git a/frameworks/native/enroll_intell_voice_engine.cpp b/frameworks/native/enroll_intell_voice_engine.cpp new file mode 100755 index 0000000..9367d45 --- /dev/null +++ b/frameworks/native/enroll_intell_voice_engine.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 + * + * 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. + */ + +#include "enroll_intell_voice_engine.h" +#include "i_intell_voice_engine.h" +#include "intell_voice_manager.h" +#include "intell_voice_log.h" + +#define LOG_TAG "EnrollIntellVoiceEngine" +using namespace std; +using namespace OHOS::IntellVoiceEngine; + +namespace OHOS { +namespace IntellVoice { +static constexpr int32_t MIN_BUFFER_SIZE = 1280; // 16 * 2 * 40ms +static constexpr int32_t CHANNEL_CNT = 1; +static constexpr int32_t BITS_PER_SAMPLE = 16; +static constexpr int32_t SAMPLE_RATE = 16000; + +EnrollIntellVoiceEngine::EnrollIntellVoiceEngine(const EnrollIntelligentVoiceEngineDescriptor &descriptor) +{ + INTELL_VOICE_LOG_INFO("enter"); + + descriptor_ = make_unique(); + if (descriptor_ != nullptr) { + descriptor_->wakeupPhrase = descriptor.wakeupPhrase; + } + IntellVoiceManager::GetInstance()->CreateIntellVoiceEngine(INTELL_VOICE_ENROLL, engine_); +} + +EnrollIntellVoiceEngine::~EnrollIntellVoiceEngine() +{ + INTELL_VOICE_LOG_INFO("enter"); + IntellVoiceManager::GetInstance()->ReleaseIntellVoiceEngine(INTELL_VOICE_ENROLL); +} + +int32_t EnrollIntellVoiceEngine::Init(const EngineConfig &config) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("IntellVoiceEngine is null"); + return -1; + } + + IntellVoiceEngineInfo info = {}; + info.wakeupPhrase = descriptor_->wakeupPhrase; + info.isPcmFromExternal = false; + info.minBufSize = MIN_BUFFER_SIZE; + info.sampleChannels = CHANNEL_CNT; + info.bitsPerSample = BITS_PER_SAMPLE; + info.sampleRate = SAMPLE_RATE; + + return engine_->Attach(info); +} + +int32_t EnrollIntellVoiceEngine::Start(const bool &isLast) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + return engine_->Start(isLast); +} + +int32_t EnrollIntellVoiceEngine::Stop() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + return engine_->Stop(); +} + +int32_t EnrollIntellVoiceEngine::Commit() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + string keyValueList = "CommitEnrollment=true"; + return engine_->SetParameter(keyValueList); +} + +int32_t EnrollIntellVoiceEngine::SetSensibility(const int32_t &sensibility) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + string keyValueList = "Sensibility=" + to_string(sensibility); + return engine_->SetParameter(keyValueList); +} + +int32_t EnrollIntellVoiceEngine::SetWakeupHapInfo(const WakeupHapInfo &info) +{ + INTELL_VOICE_LOG_INFO("enter"); + int32_t ret; + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + ret = engine_->SetParameter("wakeup_bundle_name=" + info.bundleName); + ret = engine_->SetParameter("wakeup_ability_name=" + info.abilityName); + return ret; +} + +int32_t EnrollIntellVoiceEngine::SetParameter(const string &key, const string &value) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + string keyValueList = key + "=" + value; + return engine_->SetParameter(keyValueList); +} + +int32_t EnrollIntellVoiceEngine::Release() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + + return engine_->Detach(); +} + +int32_t EnrollIntellVoiceEngine::SetCallback(shared_ptr callback) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + + callback_ = sptr(new (std::nothrow) EngineCallbackInner()); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + return -1; + } + callback_->SetEngineEventCallback(callback); + engine_->SetCallback(callback_->AsObject()); + return 0; +} +} +} \ No newline at end of file diff --git a/frameworks/native/intell_voice_manager.cpp b/frameworks/native/intell_voice_manager.cpp new file mode 100755 index 0000000..3b0b6e7 --- /dev/null +++ b/frameworks/native/intell_voice_manager.cpp @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include "intell_voice_manager.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "intell_voice_log.h" +#include "i_intell_voice_service.h" +#include "intell_voice_service_proxy.h" + +using namespace std; +using namespace OHOS::IntellVoiceEngine; +#define LOG_TAG "IntellVoiceManager" + +namespace OHOS { +namespace IntellVoice { +static sptr g_sProxy = nullptr; + +IntellVoiceManager::IntellVoiceManager() +{ + Init(); +} + +IntellVoiceManager::~IntellVoiceManager() +{ + INTELL_VOICE_LOG_INFO("enter"); +} + +IntellVoiceManager *IntellVoiceManager::GetInstance() +{ + static IntellVoiceManager manager; + return &manager; +} + +void IntellVoiceManager::Init() +{ + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (samgr == nullptr) { + INTELL_VOICE_LOG_ERROR("get sa manager failed"); + return; + } + + sptr object = samgr->GetSystemAbility(INTELL_VOICE_SERVICE_ID); + if (object == nullptr) { + INTELL_VOICE_LOG_ERROR("get system ability failed"); + return; + } + g_sProxy = iface_cast(object); + if (g_sProxy == nullptr) { + INTELL_VOICE_LOG_ERROR("init Service Proxy failed."); + } else { + INTELL_VOICE_LOG_INFO("init Service Proxy success."); + } +} + +int32_t IntellVoiceManager::CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (g_sProxy == nullptr) { + INTELL_VOICE_LOG_ERROR("IntellVoiceService Proxy is null."); + return -1; + } + return g_sProxy->CreateIntellVoiceEngine(type, inst); +} + +int32_t IntellVoiceManager::ReleaseIntellVoiceEngine(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (g_sProxy == nullptr) { + INTELL_VOICE_LOG_ERROR("IntellVoiceService Proxy is null."); + return -1; + } + return g_sProxy->ReleaseIntellVoiceEngine(type); +} +} +} \ No newline at end of file diff --git a/frameworks/native/wakeup_intell_voice_engine.cpp b/frameworks/native/wakeup_intell_voice_engine.cpp new file mode 100755 index 0000000..0f25677 --- /dev/null +++ b/frameworks/native/wakeup_intell_voice_engine.cpp @@ -0,0 +1,106 @@ +/* + * 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. + */ + +#include "wakeup_intell_voice_engine.h" +#include "i_intell_voice_engine.h" +#include "intell_voice_manager.h" +#include "intell_voice_log.h" + +using namespace std; +#define LOG_TAG "WakeupIntellVoiceEngine" + +namespace OHOS { +namespace IntellVoice { +WakeupIntellVoiceEngine::WakeupIntellVoiceEngine(const WakeupIntelligentVoiceEngineDescriptor &descriptor) +{ + INTELL_VOICE_LOG_INFO("enter"); + + descriptor_ = make_unique(); + descriptor_->needApAlgEngine = descriptor.needApAlgEngine; + descriptor_->wakeupPhrase = descriptor.wakeupPhrase; + IntellVoiceManager::GetInstance()->CreateIntellVoiceEngine(INTELL_VOICE_WAKEUP, engine_); +} + +WakeupIntellVoiceEngine::~WakeupIntellVoiceEngine() +{ + INTELL_VOICE_LOG_INFO("enter"); + IntellVoiceManager::GetInstance()->ReleaseIntellVoiceEngine(INTELL_VOICE_WAKEUP); +} + +int32_t WakeupIntellVoiceEngine::SetSensibility(const int32_t &sensibility) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + string keyValueList = "Sensibility=" + to_string(sensibility); + return engine_->SetParameter(keyValueList); +} + +int32_t WakeupIntellVoiceEngine::SetWakeupHapInfo(const WakeupHapInfo &info) +{ + INTELL_VOICE_LOG_INFO("enter"); + int32_t ret; + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + ret = engine_->SetParameter("wakeup_bundle_name=" + info.bundleName); + ret = engine_->SetParameter("wakeup_ability_name=" + info.abilityName); + return ret; +} + +int32_t WakeupIntellVoiceEngine::SetParameter(const string &key, const string &value) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + string keyValueList = key + "=" + value; + return engine_->SetParameter(keyValueList); +} + +int32_t WakeupIntellVoiceEngine::Release() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + + return engine_->Detach(); +} + +int32_t WakeupIntellVoiceEngine::SetCallback(shared_ptr callback) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (engine_ == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is null"); + return -1; + } + + callback_ = sptr(new (std::nothrow) EngineCallbackInner()); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + return -1; + } + callback_->SetEngineEventCallback(callback); + engine_->SetCallback(callback_->AsObject()); + return 0; +} +} +} \ No newline at end of file diff --git a/interfaces/inner_api/native/enroll_intell_voice_engine.h b/interfaces/inner_api/native/enroll_intell_voice_engine.h new file mode 100755 index 0000000..56c7666 --- /dev/null +++ b/interfaces/inner_api/native/enroll_intell_voice_engine.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 + * + * 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. + */ + +#ifndef ENROLL_INTELL_VOICE_ENGINE_H +#define ENROLL_INTELL_VOICE_ENGINE_H + +#include "i_intell_voice_engine.h" +#include "engine_callback_inner.h" +#include "intell_voice_info.h" + +namespace OHOS { +namespace IntellVoice { +using OHOS::IntellVoiceEngine::IIntellVoiceEngineEventCallback; +using OHOS::IntellVoiceEngine::IIntellVoiceEngine; +using OHOS::IntellVoiceEngine::EngineCallbackInner; + +struct EnrollIntelligentVoiceEngineDescriptor { + std::string wakeupPhrase; +}; + +struct EngineConfig { + std::string language; + std::string region; +}; + +class EnrollIntellVoiceEngine { +public: + EnrollIntellVoiceEngine(const EnrollIntelligentVoiceEngineDescriptor &descriptor); + ~EnrollIntellVoiceEngine(); + + int32_t Init(const EngineConfig &config); + int32_t Start(const bool &isLast); + int32_t Stop(); + int32_t Commit(); + int32_t SetSensibility(const int32_t &sensibility); + int32_t SetWakeupHapInfo(const WakeupHapInfo &info); + int32_t SetParameter(const std::string &key, const std::string &value); + int32_t GetParameter(const std::string &key); + int32_t Release(); + int32_t SetCallback(std::shared_ptr callback); + +private: + sptr engine_ = nullptr; + std::unique_ptr descriptor_ = nullptr; + sptr callback_ = nullptr; +}; +} // namespace IntellVoice +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/native/intell_voice_info.h b/interfaces/inner_api/native/intell_voice_info.h new file mode 100755 index 0000000..49badf2 --- /dev/null +++ b/interfaces/inner_api/native/intell_voice_info.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifndef INTELL_VOICE_UTILS_H +#define INTELL_VOICE_UTILS_H + +#include + +namespace OHOS { +namespace IntellVoice { +enum ServiceChangeType { + /* Service unavailable. */ + SERVICE_UNAVAILABLE = 0, +}; + +enum IntelligentVoiceEngineType { + /* Enroll engine. */ + ENROLL_ENGINE_TYPE = 0, + /* Wakeup engine. */ + WAKEUP_ENGINE_TYPE = 1, + /* Update engine. */ + UPDATE_ENGINE_TYPE = 2, +}; + +enum SensibilityType { + /* Low sensibility. */ + LOW_SENSIBILITY = 1, + /* Middle sensibility. */ + MIDDLE_SENSIBILITY = 2, + /* High sensibility. */ + HIGH_SENSIBILITY = 3, +}; + +enum EnrollIntelligentVoiceEventType { + /* Enroll None. */ + INTELLIGENT_VOICE_EVENT_ENROLL_NONE = 0, + /* Init done. */ + INTELLIGENT_VOICE_EVENT_ENROLL_INIT_DONE = 1, + /* Enroll complete. */ + INTELLIGENT_VOICE_EVENT_ENROLL_COMPLETE = 2, + /* Commit enroll complete. */ + INTELLIGENT_VOICE_EVENT_COMMIT_ENROLL_COMPLETE = 3, +}; + +enum WakeupIntelligentVoiceEventType { + /* Wakeup None. */ + INTELLIGENT_VOICE_EVENT_WAKEUP_NONE = 0, + /* Recognize complete. */ + INTELLIGENT_VOICE_EVENT_RECOGNIZE_COMPLETE = 1, +}; + +enum IntelligentVoiceErrorCode { + /* Success. */ + INTELLIGENT_VOICE_SUCCESS = 0, + /* Memory is insufficient. */ + INTELLIGENT_VOICE_NO_MEMORY = 22700101, + /* Invalid parameter. */ + INTELLIGENT_VOICE_INVALID_PARAM = 22700102, + /* Init failed. */ + INTELLIGENT_VOICE_INIT_FAILED = 22700103, + /* Enroll failed. */ + INTELLIGENT_VOICE_ENROLL_FAILED = 22700104, + /* Commit enroll failed. */ + INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED = 22700105, + /* Recognize failed. */ + INTELLIGENT_VOICE_RECOGNIZE_FAILED = 22700106, +}; + +struct WakeupHapInfo { + std::string bundleName; + std::string abilityName; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif diff --git a/interfaces/inner_api/native/intell_voice_manager.h b/interfaces/inner_api/native/intell_voice_manager.h new file mode 100755 index 0000000..b1f2818 --- /dev/null +++ b/interfaces/inner_api/native/intell_voice_manager.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 + * + * 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. + */ + +#ifndef INTELL_VOICE_MANAGER_H +#define INTELL_VOICE_MANAGER_H + +#include "i_intell_voice_engine.h" + +namespace OHOS { +namespace IntellVoice { +using namespace std; +using namespace OHOS::IntellVoiceEngine; + +class IntellVoiceManager { +public: + static IntellVoiceManager *GetInstance(); + + int32_t CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst); + int32_t ReleaseIntellVoiceEngine(IntellVoiceEngineType type); + +private: + IntellVoiceManager(); + ~IntellVoiceManager(); + + void Init(); +}; +} // namespace IntellVoice +} // namespace OHOS + +#endif diff --git a/interfaces/inner_api/native/wakeup_intell_voice_engine.h b/interfaces/inner_api/native/wakeup_intell_voice_engine.h new file mode 100755 index 0000000..9b3a224 --- /dev/null +++ b/interfaces/inner_api/native/wakeup_intell_voice_engine.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef WAKEUP_INTELL_VOICE_ENGINE_H +#define WAKEUP_INTELL_VOICE_ENGINE_H + +#include "intell_voice_info.h" +#include "i_intell_voice_engine.h" +#include "engine_callback_inner.h" + +namespace OHOS { +namespace IntellVoice { +using OHOS::IntellVoiceEngine::IIntellVoiceEngineEventCallback; +using OHOS::IntellVoiceEngine::IIntellVoiceEngine; +using OHOS::IntellVoiceEngine::EngineCallbackInner; + +struct WakeupIntelligentVoiceEngineDescriptor { + bool needApAlgEngine; + std::string wakeupPhrase; +}; + +class WakeupIntellVoiceEngine { +public: + WakeupIntellVoiceEngine(const WakeupIntelligentVoiceEngineDescriptor &descriptor); + ~WakeupIntellVoiceEngine(); + + int32_t SetSensibility(const int32_t &sensibility); + int32_t SetWakeupHapInfo(const WakeupHapInfo &info); + int32_t SetParameter(const std::string &key, const std::string &value); + int32_t GetParameter(const std::string &key); + int32_t Release(); + int32_t SetCallback(std::shared_ptr callback); + +private: + sptr engine_ = nullptr; + std::unique_ptr descriptor_ = nullptr; + sptr callback_ = nullptr; +}; +} // namespace IntellVoice +} // namespace OHOS + +#endif diff --git a/interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts b/interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts new file mode 100755 index 0000000..e869113 --- /dev/null +++ b/interfaces/kits/js/@ohos.ai.intelligentVoice.d.ts @@ -0,0 +1,823 @@ +/* + * 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 { AsyncCallback, Callback } from './@ohos.base'; + +/** + * @namespace intelligentVoice + * @since 10 + */ +declare namespace intelligentVoice { + /** + * Obtains an {@link IntelligentVoiceManager} instance. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { IntelligentVoiceManager } this {@link IntelligentVoiceManager} object. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 22700101 - No memory. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + function getIntelligentVoiceManager(): IntelligentVoiceManager; + + /** + * Implements intelligent voice management. + * @typedef IntelligentVoiceManager + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface IntelligentVoiceManager { + /** + * Obtains capability information. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Array } array of supported IntelligentVoiceEngineType. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getCapabilityInfo(): Array; + /** + * Subscribes service change events. When the state of intelligent voice service changes, + * the callback is invoked. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } type - Type of the event to listen for. Only the serviceChange event is supported. + * @param { CallbackCallback } callback - Callback is invoked when the event is triggered. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + on(type: 'serviceChange', callback: Callback): void; + /** + * Unsubscribes service change events. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } type - Type of the event to listen for. Only the serviceChange event is supported. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + off(type: 'serviceChange'): void; + } + + /** + * Enumerates service change type. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum ServiceChangeType { + /** + * Service unavailable. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + SERVICE_UNAVAILABLE = 0, + } + + /** + * Enumerates intelligent voice engine type. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum IntelligentVoiceEngineType { + /** + * Enroll engine. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + ENROLL_ENGINE_TYPE = 0, + /** + * Wakeup engine. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + WAKEUP_ENGINE_TYPE = 1, + /** + * Update engine. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + UPDATE_ENGINE_TYPE = 2, + } + + /** + * Describes enroll intelligent voice engine. + * @typedef EnrollIntelligentVoiceEngineDescriptor + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface EnrollIntelligentVoiceEngineDescriptor { + /** + * Wakeup phrase. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + wakeupPhrase: string; + } + + /** + * Describes wakeup intelligent voice engine. + * @typedef WakeupIntelligentVoiceEngineDescriptor + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface WakeupIntelligentVoiceEngineDescriptor { + /** + * Need ap algorithm engine. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + needApAlgEngine: boolean; + /** + * Wakeup phrase. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + wakeupPhrase: string; + } + + /** + * Obtains an {@link EnrollIntelligentVoiceEngine} instance. This method uses an asynchronous callback to return the EnrollIntelligentVoiceEngine instance. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { EnrollIntelligentVoiceEngineDescriptor } descriptor - descriptor indicates enroll intelligent voice engine descriptor. + * @param { AsyncCallback } callback - the callback used to return the EnrollIntelligentVoiceEngine instance. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700101 - No memory. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + function createEnrollIntelligentVoiceEngine(descriptor: EnrollIntelligentVoiceEngineDescriptor, callback: AsyncCallback): void; + + /** + * Obtains an {@link EnrollIntelligentVoiceEngine} instance. This method uses a promise to return the EnrollIntelligentVoiceEngine instance. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { EnrollIntelligentVoiceEngineDescriptor } descriptor - descriptor indicates enroll intelligent voice engine descriptor. + * @returns { Promise; } the promise used to return the EnrollIntelligentVoiceEngine instance. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700101 - No memory. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + function createEnrollIntelligentVoiceEngine(descriptor: EnrollIntelligentVoiceEngineDescriptor): Promise; + + /** + * Obtains an {@link WakeupIntelligentVoiceEngine} instance. This method uses an asynchronous callback to return the WakeupIntelligentVoiceEngine instance. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupIntelligentVoiceEngineDescriptor } descriptor - descriptor indicates wakeup intelligent voice engine descriptor. + * @param { AsyncCallback } callback - the callback used to return the WakeupIntelligentVoiceEngine instance. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700101 - No memory. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + function createWakeupIntelligentVoiceEngine(descriptor: WakeupIntelligentVoiceEngineDescriptor, callback: AsyncCallback): void; + + /** + * Obtains an {@link WakeupIntelligentVoiceEngine} instance. This method uses a promise to return the WakeupIntelligentVoiceEngine instance. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupIntelligentVoiceEngineDescriptor } descriptor - descriptor indicates wakeup intelligent voice engine descriptor. + * @returns { Promise } the promise used to return the WakeupIntelligentVoiceEngine instance. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700101 - No memory. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + function createWakeupIntelligentVoiceEngine(descriptor: WakeupIntelligentVoiceEngineDescriptor): Promise; + + /** + * Describes enroll engine config. + * @typedef EnrollEngineConfig + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface EnrollEngineConfig { + /** + * Language that enroll engine supports. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + language: string; + /** + * Region that enroll engine supports. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + region: string; + } + + /** + * Enumerates sensibility type. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum SensibilityType { + /** + * Low sensibility. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + LOW_SENSIBILITY = 1, + /** + * Middle sensibility. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + MIDDLE_SENSIBILITY = 2, + /** + * High sensibility. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + HIGH_SENSIBILITY = 3, + } + + /** + * Describes wakeup hap information. + * @typedef WakeupHapInfo + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface WakeupHapInfo { + /** + * Bundle name. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + bundleName: string; + /** + * Ability name. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + abilityName: string; + } + + /** + * Enumerates enroll intelligent voice event type. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum EnrollIntelligentVoiceEventType { + /** + * Enroll None. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_ENROLL_NONE = 0, + /** + * Init done. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_ENROLL_INIT_DONE = 1, + /** + * Enroll complete. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_ENROLL_COMPLETE = 2, + /** + * Commit enroll complete. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_COMMIT_ENROLL_COMPLETE = 3, + } + + /** + * Enumerates wakeup intelligent voice event type. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum WakeupIntelligentVoiceEventType { + /** + * Wakeup None. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_WAKEUP_NONE = 0, + /** + * Recognize complete. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_EVENT_RECOGNIZE_COMPLETE = 1, + } + + /** + * Enumerates intelligent voice error code. + * @enum {number} + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + enum IntelligentVoiceErrorCode { + /** + * Success. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_SUCCESS = 0, + /** + * Memory is insufficient. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_NO_MEMORY = 22700101, + /** + * Invalid parameter. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_INVALID_PARAM = 22700102, + /** + * Init failed. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_INIT_FAILED = 22700103, + /** + * Enroll failed. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_ENROLL_FAILED = 22700104, + /** + * Commit enroll failed. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_COMMIT_ENROLL_FAILED = 22700105, + /** + * Recognize failed. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + INTELLIGENT_VOICE_RECOGNIZE_FAILED = 22700106, + } + + /** + * Describes enrol intelligent voice engine callback information. + * @typedef EnrollIntelligentVoiceEngineCallbackInfo + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface EnrollIntelligentVoiceEngineCallbackInfo { + /** + * Enroll event id. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + eventId: EnrollIntelligentVoiceEventType; + /** + * Error code. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + errCode: IntelligentVoiceErrorCode; + /** + * Describes enroll event context. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + context: string; + } + + /** + * Describes wakeup intelligent voice engine callback information. + * @typedef WakeupIntelligentVoiceEngineCallbackInfo + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface WakeupIntelligentVoiceEngineCallbackInfo { + /** + * Wakeup event id. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + eventId: WakeupIntelligentVoiceEventType; + /** + * Error code. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + errCode: IntelligentVoiceErrorCode; + /** + * Describes wakeup event context. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + context: string; + } + + /** + * Implements enroll intelligent voice engine. + * @typedef EnrollIntelligentVoiceEngine + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface EnrollIntelligentVoiceEngine { + /** + * Obtains the supported regions, This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback> } callback - the callback used to return the supported regions. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getSupportedRegions(callback: AsyncCallback>): void; + /** + * Obtains the supported regions, This method uses a promise to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise> } the promise used to return the supported regions. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getSupportedRegions(): Promise>; + /** + * Initials the engine, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { EnrollEngineConfig } config - config indicates enroll engine configuration. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + init(config: EnrollEngineConfig, callback: AsyncCallback): void; + /** + * Initials the engine, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { EnrollEngineConfig } config - config indicates enroll engine configuration. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + init(config: EnrollEngineConfig): Promise; + /** + * Starts the engine, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { boolean } isLast - isLast indicates if it is the last time to start. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + start(isLast: boolean, callback: AsyncCallback): void; + /** + * Starts the engine, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { boolean } isLast - isLast indicates if it is the last time to start. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + start(isLast: boolean): Promise; + /** + * Stops the engine, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + stop(callback: AsyncCallback): void; + /** + * Stops the engine, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + stop(): Promise; + /** + * commit enroll, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + commit(callback: AsyncCallback): void; + /** + * commit enroll, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + commit(): Promise; + /** + * Sets wakeup hap information, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupHapInfo } info - info indicates wakeup hap information. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setWakeupHapInfo(info: WakeupHapInfo, callback: AsyncCallback): void; + /** + * Sets wakeup hap information, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupHapInfo } info - info indicates wakeup hap information. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setWakeupHapInfo(info: WakeupHapInfo): Promise; + /** + * Sets sensibility, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { SensibilityType } sensibility - sensibility to set. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setSensibility(sensibility: SensibilityType, callback: AsyncCallback): void; + /** + * Sets sensibility, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { SensibilityType } sensibility - sensibility to set. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setSensibility(sensibility: SensibilityType): Promise; + /** + * Sets an intelligent voice parameter. This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter to set. + * @param { string } value - the value of the intelligent voice parameter to set. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setParameter(key: string, value: string, callback: AsyncCallback): void; + /** + * Sets an intelligent voice parameter. This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter to set. + * @param { string } value - the value of the intelligent voice parameter to set. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setParameter(key: string, value: string): Promise; + /** + * Obtains the value of an intelligent voice parameter. This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter whose value is to be obtained. + * @param { AsyncCallback } callback - the callback used to return the value of the intelligent voice parameter. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getParameter(key: string, callback: AsyncCallback): void; + /** + * Obtains the value of an intelligent voice parameter. This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter whose value is to be obtained. + * @returns { Promise } the promise used to return the value of the intelligent voice parameter. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getParameter(key: string): Promise; + /** + * Releases the engine, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + release(callback: AsyncCallback): void; + /** + * Releases the engine, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + release(): Promise; + } + + /** + * Implements wakeup intelligent voice engine. + * @typedef WakeupIntelligentVoiceEngine + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + interface WakeupIntelligentVoiceEngine { + /** + * Obtains the supported regions, This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback> } callback - the callback used to return the supported regions. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getSupportedRegions(callback: AsyncCallback>): void; + /** + * Obtains the supported regions, This method uses a promise to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise> } the promise used to return the supported regions. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getSupportedRegions(): Promise>; + /** + * Sets wakeup hap information, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupHapInfo } info - info indicates wakeup hap information. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setWakeupHapInfo(info: WakeupHapInfo, callback: AsyncCallback): void; + /** + * Sets wakeup hap information, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { WakeupHapInfo } info - info indicates wakeup hap information. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setWakeupHapInfo(info: WakeupHapInfo): Promise; + /** + * Sets sensibility, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { SensibilityType } sensibility - sensibility to set. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setSensibility(sensibility: SensibilityType, callback: AsyncCallback): void; + /** + * Sets sensibility, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { SensibilityType } sensibility - sensibility to set. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setSensibility(sensibility: SensibilityType): Promise; + /** + * Sets an intelligent voice parameter. This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter to set. + * @param { string } value - the value of the intelligent voice parameter to set. + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setParameter(key: string, value: string, callback: AsyncCallback): void; + /** + * Sets an intelligent voice parameter. This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter to set. + * @param { string } value - the value of the intelligent voice parameter to set. + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + setParameter(key: string, value: string): Promise; + /** + * Obtains the value of an intelligent voice parameter. This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter whose value is to be obtained. + * @param { AsyncCallback } callback - the callback used to return the value of the intelligent voice parameter. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getParameter(key: string, callback: AsyncCallback): void; + /** + * Obtains the value of an intelligent voice parameter. This method uses an asynchronous callback to return the query result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } key - the key of the intelligent voice parameter whose value is to be obtained. + * @returns { Promise } the promise used to return the value of the intelligent voice parameter. + * @throws { BusinessError } 201 - Permission denied. + * @throws { BusinessError } 401 - if input parameter type or number mismatch. + * @throws { BusinessError } 22700102 - if input parameter value error. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + getParameter(key: string): Promise; + /** + * Releases the engine, This method uses an asynchronous callback to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { AsyncCallback } callback - the callback used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + release(callback: AsyncCallback): void; + /** + * Releases the engine, This method uses a promise to return the result. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @returns { Promise } the promise used to return the result. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + release(): Promise; + /** + * Subscribes wakeup intelligent voice events. When wakeup intelligent voice events reach, + * the callback is invoked. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } type - Type of the event to listen for. Only the wakeupIntelligentVoice event is supported. + * @param { Callback } callback - the callback invoked when the event is triggered. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + on(type: 'wakeupIntelligentVoiceEvent', callback: Callback): void; + /** + * Unsubscribes wakeup intelligent voice events. + * @permission ohos.permission.MANAGER_INTELLIGENT_VOICE + * @param { string } type - Type of the event to listen for. Only the wakeupIntelligentVoice event is supported. + * @throws { BusinessError } 201 - Permission denied. + * @syscap SystemCapability.AI.IntelligentVoice.Core + * @since 10 + */ + off(type: 'wakeupIntelligentVoiceEvent'); + } +} + +export default intelligentVoice; \ No newline at end of file diff --git a/llt/hdt/CMakeLists.txt b/llt/hdt/CMakeLists.txt new file mode 100755 index 0000000..0736247 --- /dev/null +++ b/llt/hdt/CMakeLists.txt @@ -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 +# +# 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. + +cmake_minimum_required(VERSION 3.13) + +project(hdt VERSION 1.0 LANGUAGES C CXX) + +# Library file compilation +add_subdirectory(depend_libs/cmake) + +# COMPONENT CMAKE +include("${CMAKE_CURRENT_SOURCE_DIR}/conf/comp.cmake") + +# PATH +set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../) +set(CLANG_DIR ${ROOT_DIR}prebuilts/clang/host/linux-x86/clang-r353983c/) + +# COMPILE_OPTIONS +set(CMAKE_CXX_COMPILER "${CLANG_DIR}/bin/clang++") +set(CMAKE_C_COMPILER "${CLANG_DIR}/bin/clang") +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") + +# INCLUDE_DIR +add_compile_options(-include memory) +include("${CMAKE_CURRENT_SOURCE_DIR}/conf/include.cmake") +include_directories(${INCLUDE_DIRECTORIES}) + + +# TEST_SOURCE_FILES +aux_source_directory(${TEST_SRC_DIR}/src/ TEST_SRC) +aux_source_directory(${TEST_SRC_DIR}/src/statemgr TEST_SRC) + + +# TEST_CASE_FILES +aux_source_directory(testcase/intell_voice_utils TEST_CASE) + +# STUB_FILE +aux_source_directory(stub STUB_FILE) + +# TARGET +add_executable(intellvoicetest ${TEST_SRC} ${TEST_CASE} ${STUB_FILE} ${DEPEND_SRC}) + +add_dependencies(intellvoicetest hilog sec utilsbase) +target_link_libraries(intellvoicetest hilog sec utilsbase) + +# MESSAGE +get_target_property(COMPILE_FLAGS intellvoicetest COMPILE_OPTIONS) +get_target_property(LINK_FLAGS intellvoicetest LINK_OPTIONS) +message(STATUS "Compiler id: ${CMAKE_CXX_COMPILER_ID}") +message(STATUS "Compile flags: ${COMPILE_FLAGS}") +message(STATUS "Link flags: ${LINK_FLAGS}") +message(STATUS "Build Type: ${CMAKE_BUILD_TYPE}") \ No newline at end of file diff --git a/llt/hdt/build.sh b/llt/hdt/build.sh new file mode 100755 index 0000000..bf01ede --- /dev/null +++ b/llt/hdt/build.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# 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. + +set -e + +CUR_DIR=$(dirname $(readlink -f $0)) +ROOT_DIR=${CUR_DIR}/../../../../../ +CLANG_DIR=${ROOT_DIR}prebuilts/clang/host/linux-x86/clang-r353983c/bin + +export PATH=$PATH:${CLANG_DIR} + +hdt comp -i --compiler clang9.0.3 +hdt build -s on -c on \ No newline at end of file diff --git a/llt/hdt/depend_libs/cmake/CMakeLists.txt b/llt/hdt/depend_libs/cmake/CMakeLists.txt new file mode 100755 index 0000000..f109e99 --- /dev/null +++ b/llt/hdt/depend_libs/cmake/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.13) + +project(lib_cmake VERSION 1.0 LANGUAGES C CXX) + +# CMAKE_WITH_ALL_COMPONENTS + +# PATH +set(ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../../) +set(CLANG_DIR ${ROOT_DIR}prebuilts/clang/host/linux-x86/clang-r353983c/) +set(INTELL_VOICE_DIR ${ROOT_DIR}foundation/ai/intelligent_voice_framework/llt/hdt/) +set(LIB_PATH ${INTELL_VOICE_DIR}/build) + +# COMPILE_OPTIONS +set(CMAKE_CXX_COMPILER "${CLANG_DIR}/bin/clang++") +set(CMAKE_C_COMPILER "${CLANG_DIR}/bin/clang") +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99") +add_compile_options(-Wno-c++11-narrowing) + +include("libhilog.cmake") +include("libsec.cmake") +include("libutilsbase.cmake") \ No newline at end of file diff --git a/llt/hdt/depend_libs/cmake/libhilog.cmake b/llt/hdt/depend_libs/cmake/libhilog.cmake new file mode 100755 index 0000000..d18396c --- /dev/null +++ b/llt/hdt/depend_libs/cmake/libhilog.cmake @@ -0,0 +1,31 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. +# Description: liblog.cmake +# Create: 2022-8-15 + +cmake_minimum_required(VERSION 3.13) +set(HILOG_DIR ${ROOT_DIR}base/hiviewdfx/hilog/) +set(HILOG_SRC_DIR ${ROOT_DIR}base/hiviewdfx/hilog/frameworks/libhilog/) + +include_directories(${ROOT_DIR}third_party/bounds_checking_function/include) +include_directories(${HILOG_DIR}frameworks/include/) +include_directories(${HILOG_DIR}frameworks/libhilog/include/) +include_directories(${HILOG_DIR}frameworks/libhilog/socket/include/) +include_directories(${HILOG_DIR}frameworks/libhilog/param/include/) +include_directories(${HILOG_DIR}frameworks/libhilog/utils/include/) +include_directories(${HILOG_DIR}frameworks/libhilog/vsnprintf/include/) +include_directories(${HILOG_DIR}interfaces/native/innerkits/include/) + +set(LIBRARY_OUTPUT_PATH ${LIB_PATH}) +set(MACRO_DEFINITION_LOG -D__LINUX__) + +# TEST_SOURCE_FILES +file(GLOB LOG_SRCS + ${HILOG_SRC_DIR}hilog.cpp + ${HILOG_SRC_DIR}hilog_printf.cpp + ${HILOG_SRC_DIR}utils/log_print.cpp + ${HILOG_SRC_DIR}utils/log_utils.cpp + ${HILOG_SRC_DIR}vsnprintf/vsnprintf_s_p.cpp) + +add_library(hilog STATIC ${LOG_SRCS}) +target_compile_definitions(hilog PRIVATE ${MACRO_DEFINITION_LOG}) +set_target_properties(hilog PROPERTIES COMPILE_FLAGS "-w") \ No newline at end of file diff --git a/llt/hdt/depend_libs/cmake/libsec.cmake b/llt/hdt/depend_libs/cmake/libsec.cmake new file mode 100755 index 0000000..492cee5 --- /dev/null +++ b/llt/hdt/depend_libs/cmake/libsec.cmake @@ -0,0 +1,27 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. +# Description: liblog.cmake +# Create: 2022-8-15 + +cmake_minimum_required(VERSION 3.13) +set(SEC_DIR ${ROOT_DIR}third_party/bounds_checking_function/) + +include_directories(${SEC_DIR}include) + +set(LIBRARY_OUTPUT_PATH ${LIB_PATH}) + +set(MACRO_DEFINITION_LOG + -D__LINUX__ + -D_INC_STRING_S + -D_INC_WCHAR_S + -D_SECIMP=// + -D_STDIO_S_DEFINED + -D_INC_STDIO_S + -D_INC_STDLIB_S + -D_INC_MEMORY_S) + +# TEST_SOURCE_FILES +aux_source_directory(${SEC_DIR}/src SEC_SRCS) + +add_library(sec STATIC ${SEC_SRCS}) +target_compile_definitions(sec PRIVATE ${MACRO_DEFINITION_LOG}) +set_target_properties(sec PROPERTIES COMPILE_FLAGS "-w") \ No newline at end of file diff --git a/llt/hdt/depend_libs/cmake/libutilsbase.cmake b/llt/hdt/depend_libs/cmake/libutilsbase.cmake new file mode 100755 index 0000000..06ac54a --- /dev/null +++ b/llt/hdt/depend_libs/cmake/libutilsbase.cmake @@ -0,0 +1,24 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved. +# Description: liblog.cmake +# Create: 2022-8-15 + +cmake_minimum_required(VERSION 3.13) +set(UTILSBASE_DIR ${ROOT_DIR}commonlibrary/c_utils/base/) + +include_directories(${UTILSBASE_DIR}include) +include_directories(${UTILSBASE_DIR}src) +include_directories(${ROOT_DIR}kernel/linux-5.10-lts/make_output/usr/include/) + +set(LIBRARY_OUTPUT_PATH ${LIB_PATH}) + +# TEST_SOURCE_FILES +aux_source_directory(${UTILSBASE_DIR}/src UTILSBASE_DIR_SRCS) + +file(GLOB SRC_BLACK_LIST + ${UTILSBASE_DIR}/src/file_ex.cpp) + +list(REMOVE_ITEM UTILSBASE_DIR_SRCS ${SRC_BLACK_LIST}) + +add_library(utilsbase STATIC ${UTILSBASE_DIR_SRCS}) +target_compile_options(utilsbase PRIVATE -include functional -includelimits.h) +set_target_properties(utilsbase PROPERTIES COMPILE_FLAGS "-w") \ No newline at end of file diff --git a/llt/hdt/depend_libs/src/file_ex.cpp b/llt/hdt/depend_libs/src/file_ex.cpp new file mode 100755 index 0000000..65b469c --- /dev/null +++ b/llt/hdt/depend_libs/src/file_ex.cpp @@ -0,0 +1,346 @@ +/* + * 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. + */ + +#include "file_ex.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "directory_ex.h" +#include "utils_log.h" + +using namespace std; + +const int MAX_FILE_LENGTH = 32 * 1024 * 1024; + +namespace OHOS { +bool LoadStringFromFile(const string& filePath, string& content) +{ + ifstream file(filePath.c_str()); + if (!file.is_open()) { + UTILS_LOGD("open file failed! filePath:%{public}s", filePath.c_str()); + return false; + } + + file.seekg(0, ios::end); + const long fileLength = file.tellg(); + if (fileLength > MAX_FILE_LENGTH) { + UTILS_LOGD("invalid file length(%{public}ld)!", fileLength); + return false; + } + + content.clear(); + file.seekg(0, ios::beg); + copy(istreambuf_iterator(file), istreambuf_iterator(), back_inserter(content)); + return true; +} + +string GetFileNameByFd(const int fd) +{ + if (fd <= 0) { + return string(); + } + + string fdPath = "/proc/self/fd/" + std::to_string(fd); + char fileName[PATH_MAX + 1] = {0}; + + int ret = readlink(fdPath.c_str(), fileName, PATH_MAX); + if (ret < 0 || ret > PATH_MAX) { + UTILS_LOGD("Get fileName failed, ret is: %{public}d!", ret); + return string(); + } + fileName[ret] = '\0'; + return string(fileName); +} + +bool LoadStringFromFdToFile(int fd, string& content) +{ + string fileName = GetFileNameByFd(fd); + if (fileName.empty()) { + UTILS_LOGD("LoadStringFromFd get file name by fd failed!"); + return false; + } + + if (!LoadStringFromFile(fileName, content)) { + UTILS_LOGE("LoadStringFromFd get string from file failed!"); + return false; + } + return true; +} + +bool LoadStringFromFd(int fd, string& content) +{ + if (fd <= 0) { + UTILS_LOGD("invalid fd:%{public}d", fd); + return false; + } + + const long fileLength = lseek(fd, 0, SEEK_END); + if (fileLength > MAX_FILE_LENGTH) { + UTILS_LOGE("invalid file length(%{public}ld)!", fileLength); + return false; + } + + // lseek is not support the linux file node + if (fileLength < 0) { + return LoadStringFromFdToFile(fd, content); + } + + if (fileLength == 0) { + return true; + } + + content.resize(fileLength); + int loc = lseek(fd, 0, SEEK_SET); + if (loc == -1) { + UTILS_LOGE("lseek file to begin failed!"); + return false; + } + + const long len = read(fd, content.data(), fileLength); + if (len != fileLength) { + UTILS_LOGE("the length read from file is not equal to fileLength!len:%{public}ld,fileLen:%{public}ld", + len, fileLength); + return false; + } + + return true; +} + +bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated /* = true */) +{ + if (content.empty()) { + UTILS_LOGI("content is empty, no need to save!"); + return true; + } + + ofstream file; + if (truncated) { + file.open(filePath.c_str(), ios::out | ios::trunc); + } else { + file.open(filePath.c_str(), ios::out | ios::app); + } + + if (!file.is_open()) { + UTILS_LOGD("open file failed! filePath:%{private}s", filePath.c_str()); + return false; + } + + file.write(content.c_str(), content.length()); + if (file.fail()) { + UTILS_LOGE("write content to file failed!file:%{private}s, content:%{private}s", + filePath.c_str(), content.c_str()); + return false; + } + return true; +} + +bool SaveStringToFd(int fd, const std::string& content) +{ + if (fd <= 0) { + UTILS_LOGD("invalid fd:%{public}d", fd); + return false; + } + + if (content.empty()) { + UTILS_LOGI("content is empty, no need to save!"); + return true; + } + + const long len = write(fd, content.c_str(), content.length()); + if (len < 0) { + UTILS_LOGE("write file failed!errno:%{public}d, err:%{public}s", errno, strerror(errno)); + return false; + } + + if (static_cast(len) != content.length()) { + UTILS_LOGE("the length write to file is not equal to fileLength!len:%{public}ld, fileLen:%{public}zu", + len, content.length()); + return false; + } + + return true; +} + +bool LoadBufferFromNodeFile(const string& filePath, vector& content) +{ + string realPath; + if (!PathToRealPath(filePath, realPath)) { + UTILS_LOGD("filePath to realPath failed! filePath:%{private}s", filePath.c_str()); + return false; + } + + FILE *fp = fopen(realPath.c_str(), "r"); + if (fp == nullptr) { + UTILS_LOGD("open file failed! filePath:%{private}s", realPath.c_str()); + return false; + } + + int byteCount = 1; + while (!feof(fp)) { + if (byteCount > MAX_FILE_LENGTH) { + UTILS_LOGE("LoadBufferFromNodeFile invalid file length(%{public}d)!", byteCount); + fclose(fp); + fp = nullptr; + content.clear(); + return false; + } + char ch = fgetc(fp); + content.push_back(ch); + byteCount++; + } + + fclose(fp); + fp = nullptr; + return true; +} + +/* load file to buffer. If the buffer is not empty,then overwrite */ +bool LoadBufferFromFile(const string& filePath, vector& content) +{ + ifstream file; + file.open(filePath.c_str(), ios::in | ios::binary); + if (!file.is_open()) { + UTILS_LOGD("open file failed! filePath:%{private}s", filePath.c_str()); + return false; + } + + file.seekg(0, std::ios::end); + const long fileLength = file.tellg(); + if (fileLength > MAX_FILE_LENGTH) { + UTILS_LOGD("invalid file length(%{public}ld)!", fileLength); + return false; + } + + // lseek is not support the linux file node + if (fileLength < 0) { + return LoadBufferFromNodeFile(filePath, content); + } + + if (fileLength == 0) { + content.clear(); + return true; + } + + file.seekg(0, std::ios::beg); + if (file.fail()) { + UTILS_LOGE("seekg file to begin failed!filePath:%{private}s", filePath.c_str()); + return false; + } + + content.resize(fileLength); + file.read(&content[0], fileLength); + return true; +} + +bool SaveBufferToFile(const string& filePath, const vector& content, bool truncated /* = true */) +{ + if (content.empty()) { + UTILS_LOGI("content is empty, no need to save!"); + return true; + } + + // if the file is not exist,create it first! + ios_base::openmode mode = truncated ? (ios::out | ios::binary | ios::trunc) : (ios::out | ios::binary | ios::app); + ofstream file; + file.open(filePath.c_str(), mode); + if (!file.is_open()) { + UTILS_LOGD("open file failed! filePath:%{private}s, mode:%{private}d", filePath.c_str(), mode); + return false; + } + + file.write(&content[0], content.size()); + return true; +} + +bool FileExists(const string& fileName) +{ + return (access(fileName.c_str(), F_OK) == 0); +} + +bool StringExistsInFile(const string& fileName, const string& subStr, bool caseSensitive /* = true */) +{ + if (subStr.empty()) { + UTILS_LOGD("String is empty"); + return false; + } + + string str; + if (!LoadStringFromFile(fileName, str)) { + UTILS_LOGD("File load fail, filePath:%{private}s", fileName.c_str()); + return false; + } + + if (caseSensitive) { + return (str.find(subStr) != string::npos); + } + + string strlower(str); + string sublower(subStr); + transform(str.begin(), str.end(), strlower.begin(), ::tolower); + transform(subStr.begin(), subStr.end(), sublower.begin(), ::tolower); + return (strlower.find(sublower) != string::npos); +} + +int CountStrInStr(const string& str, const string& subStr) +{ + if (subStr.empty()) { + UTILS_LOGD("subStr is empty"); + return 0; + } + + size_t position = 0; + int count = 0; + size_t length = subStr.length(); + while ((position = str.find(subStr, position)) != string::npos) { + position += length; + count++; + } + + return count; +} + +int CountStrInFile(const string& fileName, const string& subStr, bool caseSensitive /* = true */) +{ + if (subStr.empty()) { + UTILS_LOGD("String is empty"); + return -1; + } + + string str; + if (!LoadStringFromFile(fileName, str)) { + UTILS_LOGD("File load fail, filePath:%{private}s", fileName.c_str()); + return -1; + } + + // If case-insensitive, strings are converted to lowercase. + if (caseSensitive) { + return CountStrInStr(str, subStr); + } + + string strlower(str); + string sublower(subStr); + transform(str.begin(), str.end(), strlower.begin(), ::tolower); + transform(subStr.begin(), subStr.end(), sublower.begin(), ::tolower); + return CountStrInStr(strlower, sublower); +} +} diff --git a/llt/hdt/run.sh b/llt/hdt/run.sh new file mode 100755 index 0000000..719a0c7 --- /dev/null +++ b/llt/hdt/run.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# 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. + +set -e + +CUR_DIR=$(dirname $(readlink -f $0)) +CUR_DIR=$(cd ${CUR_DIR}; pwd) +ROOT_DIR=${CUR_DIR}/../../../../../ +ROOT_DIR=$(cd ${ROOT_DIR}; pwd) + +hdt run +hdt report --args='--filter='${TESTING_SRC_DIR}' --gcov-executable "'${ROOT_DIR}/'prebuilts/clang/host/linux-x86/clang-r353983c/bin/llvm-cov gcov"' \ No newline at end of file diff --git a/llt/hdt/stub/message_parcel.cpp b/llt/hdt/stub/message_parcel.cpp new file mode 100755 index 0000000..4406310 --- /dev/null +++ b/llt/hdt/stub/message_parcel.cpp @@ -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 + * + * 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. + */ + +#include "message_parcel.h" + +namespace OHOS { +bool WriteFileDescriptor(int fd) +{ + (void)fd; + return false; +} + +int ReadFileDescriptor() +{ + return 0; +} +} // namespace OHOS diff --git a/llt/hdt/testcase/intell_voice_utils/test_time_util.cpp b/llt/hdt/testcase/intell_voice_utils/test_time_util.cpp new file mode 100755 index 0000000..8f88ef2 --- /dev/null +++ b/llt/hdt/testcase/intell_voice_utils/test_time_util.cpp @@ -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 + * + * 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. + */ + +#define CATCH_CONFIG_MAIN +#include "catch2/catch.hpp" + +#include "time_util.h" + +namespace OHOS { +namespace IntellVoiceUtils { +TEST_CASE("GetCurrTime", "intell_voice_time") { + enum TimeFormat format = TIME_FORMAT_DEFAULT; + std::string str = TimeUtil::GetCurrTime(format); + REQUIRE(str != ""); + + SECTION("continuous time format") { + TimeFormat format = TIME_FORMAT_CONTINOUS; + str = TimeUtil::GetCurrTime(format); + REQUIRE(str != ""); + } + SECTION("standard time format") { + TimeFormat format = TIME_FORMAT_STANDARD; + str = TimeUtil::GetCurrTime(format); + REQUIRE(str != ""); + } +} +} +} \ No newline at end of file diff --git a/sa_profile/2688.xml b/sa_profile/2688.xml new file mode 100755 index 0000000..b991862 --- /dev/null +++ b/sa_profile/2688.xml @@ -0,0 +1,25 @@ + + + + intell_voice_service + + 2688 + /system/lib64/libintell_voice_server.z.so + true + false + 1 + + \ No newline at end of file diff --git a/sa_profile/BUILD.gn b/sa_profile/BUILD.gn new file mode 100755 index 0000000..bc8f697 --- /dev/null +++ b/sa_profile/BUILD.gn @@ -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 +# +# 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("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("intell_voice_service_sa_profile") { + sources = [ "2688.xml" ] + part_name = "intelligent_voice_framework" +} diff --git a/services/BUILD.gn b/services/BUILD.gn new file mode 100755 index 0000000..29029a8 --- /dev/null +++ b/services/BUILD.gn @@ -0,0 +1,146 @@ +# 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("//build/ohos.gni") + +ohos_shared_library("intell_voice_proxy") { + sources = [ + "intell_voice_engine/proxy/engine_callback_inner.cpp", + "intell_voice_engine/proxy/intell_voice_engine_callback_stub.cpp", + "intell_voice_engine/proxy/intell_voice_engine_proxy.cpp", + "intell_voice_engine/proxy/intell_voice_service_proxy.cpp", + ] + + include_dirs = [ + "intell_voice_engine", + "intell_voice_engine/proxy", + "//foundation/ai/intelligent_voice_framework/utils", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + public_deps = [ "//drivers/interface/intelligent_voice/engine/v1_0:intell_voice_engine_idl_headers" ] + + external_deps = [ + "c_utils:utils", + "hdf_core:libhdf_host", + "hdf_core:libhdf_ipc_adapter", + "hdf_core:libhdf_utils", + "hdf_core:libhdi", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} + +ohos_shared_library("intell_voice_server") { + configs = [ "//build/config/compiler:exceptions" ] + + sources = [ + "intell_voice_engine/server/base/adapter_callback_service.cpp", + "intell_voice_engine/server/base/audio_source.cpp", + "intell_voice_engine/server/base/engine_base.cpp", + "intell_voice_engine/server/base/engine_factory.cpp", + "intell_voice_engine/server/base/file_source.cpp", + "intell_voice_engine/server/enroll/enroll_adapter_listener.cpp", + "intell_voice_engine/server/enroll/enroll_engine.cpp", + "intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.cpp", + "intell_voice_engine/server/sa/intell_voice_engine_stub.cpp", + "intell_voice_engine/server/sa/intell_voice_service.cpp", + "intell_voice_engine/server/sa/intell_voice_service_manager.cpp", + "intell_voice_engine/server/sa/intell_voice_service_stub.cpp", + "intell_voice_engine/server/utils/history_info_mgr.cpp", + "intell_voice_engine/server/utils/service_db_helper.cpp", + "intell_voice_engine/server/utils/switch_observer.cpp", + "intell_voice_engine/server/utils/switch_provider.cpp", + "intell_voice_engine/server/utils/system_event_observer.cpp", + "intell_voice_engine/server/wakeup/wakeup_adapter_listener.cpp", + "intell_voice_engine/server/wakeup/wakeup_engine.cpp", + "intell_voice_trigger/server/connector_mgr/trigger_callback_impl.cpp", + "intell_voice_trigger/server/connector_mgr/trigger_connector.cpp", + "intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.cpp", + "intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.cpp", + "intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.cpp", + "intell_voice_trigger/server/trigger_base_type.cpp", + "intell_voice_trigger/server/trigger_db_helper.cpp", + "intell_voice_trigger/server/trigger_detector.cpp", + "intell_voice_trigger/server/trigger_detector_callback.cpp", + "intell_voice_trigger/server/trigger_detector_recognition_callback.cpp", + "intell_voice_trigger/server/trigger_helper.cpp", + "intell_voice_trigger/server/trigger_manager.cpp", + "intell_voice_trigger/server/trigger_service.cpp", + ] + + public_deps = [ + "//drivers/interface/intelligent_voice/engine/v1_0:intell_voice_engine_idl_headers", + "//drivers/interface/intelligent_voice/trigger/v1_0:intell_voice_trigger_idl_headers", + ] + + include_dirs = [ + "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiocommon/include", + "//foundation/multimedia/audio_framework/interfaces/inner_api/native/audiocapturer/include", + "//foundation/ai/intelligent_voice_framework/utils", + "intell_voice_engine", + "intell_voice_engine/server/base", + "intell_voice_engine/server/enroll", + "intell_voice_engine/server/sa", + "intell_voice_engine/server/utils", + "intell_voice_engine/server/wakeup", + "intell_voice_trigger/server", + "intell_voice_trigger/server/connector_mgr", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//drivers/interface/intelligent_voice/engine/v1_0:libintell_voice_engine_proxy_1.0", + "//drivers/interface/intelligent_voice/trigger/v1_0:libintell_voice_trigger_proxy_1.0", + "//foundation/ability/ability_runtime/frameworks/native/appkit:app_context", + "//foundation/ability/ability_runtime/interfaces/inner_api/dataobs_manager:dataobs_manager", + "//foundation/ai/intelligent_voice_framework/utils:intell_voice_utils", + "//foundation/multimedia/audio_framework/frameworks/native/audiocapturer:audio_capturer", + ] + + external_deps = [ + "ability_base:want", + "ability_base:zuri", + "ability_runtime:ability_manager", + "access_token:libaccesstoken_sdk", + "c_utils:utils", + "common_event_service:cesfwk_innerkits", + "data_share:datashare_consumer", + "eventhandler:libeventhandler", + "hdf_core:libhdi", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "kv_store:distributeddata_inner", + "relational_store:native_rdb", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] + + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} diff --git a/services/etc/BUILD.gn b/services/etc/BUILD.gn new file mode 100755 index 0000000..789d867 --- /dev/null +++ b/services/etc/BUILD.gn @@ -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 +# +# 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("//build/ohos.gni") + +ohos_prebuilt_etc("intell_voice_service.rc") { + source = "intell_voice_service.cfg" + relative_install_dir = "init" + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} diff --git a/services/etc/intell_voice_service.cfg b/services/etc/intell_voice_service.cfg new file mode 100755 index 0000000..59e3f29 --- /dev/null +++ b/services/etc/intell_voice_service.cfg @@ -0,0 +1,22 @@ +{ + "jobs" : [{ + "name" : "post-fs-data", + "cmds" : [ + "mkdir /data/service/el1/public/database 0711 ddms ddms", + "mkdir /data/service/el1/public/database/intell_voice_service_manager 02770 intell_voice ddms", + "mkdir /data/data/intell_voice 0760 intell_voice intell_voice", + "mkdir /data/data/intell_voice/pcm_data 0760 intell_voice intell_voice", + "start intell_voice_service" + ] + } + ], + "services" : [{ + "name" : "intell_voice_service", + "path" : ["/system/bin/sa_main", "/system/profile/intell_voice_service.xml"], + "uid" : "intell_voice", + "gid" : ["system","intell_voice"], + "permission" : ["ohos.permission.MANAGE_INTELLIGENT_VOICE"], + "disabled" : 1 + } + ] +} \ No newline at end of file diff --git a/services/etc/intell_voice_service.rc b/services/etc/intell_voice_service.rc new file mode 100755 index 0000000..5d6ca72 --- /dev/null +++ b/services/etc/intell_voice_service.rc @@ -0,0 +1,8 @@ +on post-fs-data + start intell_voice_service +service intell_voice_service /system/bin/sa_main /system/profile/intell_voice_service.xml + class z_core + user system + group system shell + seclabel u:r:intell_voice_service:s0 + onrestart restart intell_voice_hal_1_0 \ No newline at end of file diff --git a/services/intell_voice_engine/i_intell_voice_engine.h b/services/intell_voice_engine/i_intell_voice_engine.h new file mode 100755 index 0000000..68f39dc --- /dev/null +++ b/services/intell_voice_engine/i_intell_voice_engine.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 + * + * 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. + */ + +#ifndef IINTELL_VOICE_ENGINE_H +#define IINTELL_VOICE_ENGINE_H +#include "iremote_broker.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceEngine { +enum IntellVoiceEngineType { + INTELL_VOICE_ENROLL = 0, + INTELL_VOICE_WAKEUP, + INTELL_VOICE_UPDATE, + ENGINE_TYPE_BUT +}; + +struct IntellVoiceEngineInfo { + std::string wakeupPhrase; + bool isPcmFromExternal { false }; + int32_t minBufSize { 0 }; + int32_t sampleChannels { 0 }; + int32_t bitsPerSample { 0 }; + int32_t sampleRate { 0 }; +}; + +class IIntellVoiceEngine : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"HDI.IntellVoice.Engine"); + + enum { + INTELL_VOICE_ENGINE_SET_CALLBACK = 0, + INTELL_VOICE_ENGINE_ATTACH, + INTELL_VOICE_ENGINE_DETACH, + INTELL_VOICE_ENGINE_SET_PARAMETER, + INTELL_VOICE_ENGINE_GET_PARAMETER, + INTELL_VOICE_ENGINE_START, + INTELL_VOICE_ENGINE_STOP, + INTELL_VOICE_ENGINE_WRITE_AUDIO + }; + + virtual void SetCallback(sptr IntellVoiceEngineStub) = 0; + virtual int32_t Attach(const IntellVoiceEngineInfo &info) = 0; + virtual int32_t Detach(void) = 0; + virtual int32_t SetParameter(const std::string &keyValueList) = 0; + virtual std::string GetParameter(const std::string &key) = 0; + virtual int32_t Start(bool isLast) = 0; + virtual int32_t Stop(void) = 0; + virtual int32_t WriteAudio(const uint8_t *buffer, uint32_t size) = 0; +}; +} +} + +#endif diff --git a/services/intell_voice_engine/i_intell_voice_engine_callback.h b/services/intell_voice_engine/i_intell_voice_engine_callback.h new file mode 100755 index 0000000..4def000 --- /dev/null +++ b/services/intell_voice_engine/i_intell_voice_engine_callback.h @@ -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 + * + * 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. + */ + +#ifndef I_INTELL_VOICE_ENGINE_CALLBACK_H +#define I_INTELL_VOICE_ENGINE_CALLBACK_H + +#include "iremote_broker.h" +#include "v1_0/intell_voice_engine_types.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent; + +class IIntellVoiceEngineEventCallback { +public: + virtual ~IIntellVoiceEngineEventCallback() = default; + virtual void OnEvent(const IntellVoiceEngineCallBackEvent ¶m) = 0; +}; + +class IIntelligentVoiceEngineCallback : public IRemoteBroker { +public: + virtual void OnIntellVoiceEngineEvent(const IntellVoiceEngineCallBackEvent &event) = 0; + enum Code { + ON_INTELL_VOICE_ENGINE_EVENT = 0, + }; + +public: + DECLARE_INTERFACE_DESCRIPTOR(u"IIntelligentVoiceEngineCallback"); +}; +} // namespace IntellVoice +} // namespace OHOS +#endif // I_INTELL_VOICE_ENGINE_CALLBACK_H diff --git a/services/intell_voice_engine/i_intell_voice_service.h b/services/intell_voice_engine/i_intell_voice_service.h new file mode 100755 index 0000000..50142fe --- /dev/null +++ b/services/intell_voice_engine/i_intell_voice_service.h @@ -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 + * + * 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. + */ + +#ifndef IINTELL_VOICE_SERVICE_H +#define IINTELL_VOICE_SERVICE_H +#include "iremote_broker.h" +#include "i_intell_voice_engine.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IIntellVoiceService : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"IntellVoiceFramework.Service"); + + enum { + HDI_INTELL_VOICE_SERVICE_CREATE_ENGINE = 0, + HDI_INTELL_VOICE_SERVICE_RELEASE_ENGINE, + }; + + virtual int32_t CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) = 0; + virtual int32_t ReleaseIntellVoiceEngine(IntellVoiceEngineType type) = 0; +}; +} +} +#endif diff --git a/services/intell_voice_engine/proxy/engine_callback_inner.cpp b/services/intell_voice_engine/proxy/engine_callback_inner.cpp new file mode 100755 index 0000000..96387ab --- /dev/null +++ b/services/intell_voice_engine/proxy/engine_callback_inner.cpp @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "engine_callback_inner.h" +#include "intell_voice_log.h" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; +#define LOG_TAG "EngineCallbackInner" + +namespace OHOS { +namespace IntellVoiceEngine { +void EngineCallbackInner::OnIntellVoiceEngineEvent(const IntellVoiceEngineCallBackEvent &event) +{ + INTELL_VOICE_LOG_INFO("receive event"); + if (cb_ == nullptr) { + INTELL_VOICE_LOG_INFO("cb is null"); + return; + } + cb_->OnEvent(event); +} + +void EngineCallbackInner::SetEngineEventCallback(std::shared_ptr cb) +{ + cb_ = cb; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/proxy/engine_callback_inner.h b/services/intell_voice_engine/proxy/engine_callback_inner.h new file mode 100755 index 0000000..57a5997 --- /dev/null +++ b/services/intell_voice_engine/proxy/engine_callback_inner.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +#ifndef ENGINE_CALLBACK_INNER_H +#define ENGINE_CALLBACK_INNER_H + +#include +#include "intell_voice_engine_callback_stub.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class EngineCallbackInner final : public IntellVoiceEngineCallbackStub { +public: + void OnIntellVoiceEngineEvent( + const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event) override; + void SetEngineEventCallback(std::shared_ptr cb); +private: + std::shared_ptr cb_; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.cpp b/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.cpp new file mode 100755 index 0000000..e6b0779 --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.cpp @@ -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 + * + * 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. + */ + +#include "intell_voice_engine_callback_stub.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceEngineCallbackStub" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; + +namespace OHOS { +namespace IntellVoiceEngine { +int IntellVoiceEngineCallbackStub::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + INTELL_VOICE_LOG_INFO("OnRemoteRequest"); + if (data.ReadInterfaceToken() != IIntelligentVoiceEngineCallback::GetDescriptor()) { + INTELL_VOICE_LOG_ERROR("ReadInterfaceToken failed"); + return -1; + } + IIntelligentVoiceEngineCallback::Code msgCode = static_cast(code); + switch (msgCode) { + case ON_INTELL_VOICE_ENGINE_EVENT: { + OnIntellVoiceEngineEventInner(data); + reply.WriteInt32(0); + break; + } + default: { + INTELL_VOICE_LOG_WARN("invalid msgCode:%{public}d", msgCode); + reply.WriteInt32(-1); + break; + } + } + return 0; +} + +void IntellVoiceEngineCallbackStub::OnIntellVoiceEngineEventInner(MessageParcel &data) +{ + IntellVoiceEngineCallBackEvent event = { + .msgId = static_cast(data.ReadInt32()), + .result = static_cast(data.ReadInt32()), + .info = data.ReadString(), + }; + OnIntellVoiceEngineEvent(event); +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.h b/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.h new file mode 100755 index 0000000..46a304b --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_engine_callback_stub.h @@ -0,0 +1,32 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_ENGINE_CALLBACK_STUB_H +#define INTELL_VOICE_ENGINE_CALLBACK_STUB_H + +#include "iremote_stub.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceEngineCallbackStub : public IRemoteStub { +public: + int OnRemoteRequest(uint32_t code, MessageParcel &data, + MessageParcel &reply, MessageOption &option) override; +private: + void OnIntellVoiceEngineEventInner(MessageParcel &data); +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/proxy/intell_voice_engine_proxy.cpp b/services/intell_voice_engine/proxy/intell_voice_engine_proxy.cpp new file mode 100755 index 0000000..4b6bbe7 --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_engine_proxy.cpp @@ -0,0 +1,132 @@ +/* + * 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. + */ + +#include "intell_voice_engine_proxy.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceEngineProxy" + +namespace OHOS { +namespace IntellVoiceEngine { +void IntellVoiceEngineProxy::SetCallback(sptr object) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + if (object == nullptr) { + INTELL_VOICE_LOG_ERROR("object is null"); + return; + } + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + data.WriteRemoteObject(object); + Remote()->SendRequest(INTELL_VOICE_ENGINE_SET_CALLBACK, data, reply, option); +} + +int32_t IntellVoiceEngineProxy::Attach(const IntellVoiceEngineInfo &info) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + data.WriteString(info.wakeupPhrase); + data.WriteBool(info.isPcmFromExternal); + data.WriteInt32(info.minBufSize); + data.WriteInt32(info.sampleChannels); + data.WriteInt32(info.bitsPerSample); + data.WriteInt32(info.sampleRate); + + Remote()->SendRequest(INTELL_VOICE_ENGINE_ATTACH, data, reply, option); + + INTELL_VOICE_LOG_INFO("Attach call"); + return reply.ReadInt32(); +} + +int32_t IntellVoiceEngineProxy::Detach(void) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + Remote()->SendRequest(INTELL_VOICE_ENGINE_DETACH, data, reply, option); + return reply.ReadInt32(); +} + +int32_t IntellVoiceEngineProxy::SetParameter(const std::string &keyValueList) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + data.WriteString(keyValueList); + Remote()->SendRequest(INTELL_VOICE_ENGINE_SET_PARAMETER, data, reply, option); + return reply.ReadInt32(); +} + +std::string IntellVoiceEngineProxy::GetParameter(const std::string &key) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + data.WriteString(key); + + Remote()->SendRequest(INTELL_VOICE_ENGINE_GET_PARAMETER, data, reply, option); + return reply.ReadString(); +} + +int32_t IntellVoiceEngineProxy::Start(bool isLast) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + + Remote()->SendRequest(INTELL_VOICE_ENGINE_START, data, reply, option); + return reply.ReadInt32(); +} + +int32_t IntellVoiceEngineProxy::Stop(void) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + + Remote()->SendRequest(INTELL_VOICE_ENGINE_STOP, data, reply, option); + return reply.ReadInt32(); +} + +int32_t IntellVoiceEngineProxy::WriteAudio(const uint8_t *buffer, uint32_t size) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceEngine::GetDescriptor()); + data.WriteUint32(size); + data.WriteBuffer(buffer, size); + + Remote()->SendRequest(INTELL_VOICE_ENGINE_WRITE_AUDIO, data, reply, option); + return reply.ReadInt32(); +} +} +} diff --git a/services/intell_voice_engine/proxy/intell_voice_engine_proxy.h b/services/intell_voice_engine/proxy/intell_voice_engine_proxy.h new file mode 100755 index 0000000..2c2a65c --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_engine_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 + * + * 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. + */ + +#ifndef INTELL_VOICE_ENGINE_PROXY_H +#define INTELL_VOICE_ENGINE_PROXY_H + +#include +#include "i_intell_voice_engine.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceEngineProxy : public IRemoteProxy { +public: + explicit IntellVoiceEngineProxy(const sptr &impl) : IRemoteProxy(impl) {}; + virtual ~IntellVoiceEngineProxy() {}; + void SetCallback(sptr object) override; + int32_t Attach(const IntellVoiceEngineInfo &info) override; + int32_t Detach(void) override; + int32_t SetParameter(const std::string &keyValueList) override; + std::string GetParameter(const std::string &key) override; + int32_t Start(bool isLast) override; + int32_t Stop(void) override; + int32_t WriteAudio(const uint8_t *buffer, uint32_t size) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} + +#endif diff --git a/services/intell_voice_engine/proxy/intell_voice_service_proxy.cpp b/services/intell_voice_engine/proxy/intell_voice_service_proxy.cpp new file mode 100755 index 0000000..cb1c555 --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_service_proxy.cpp @@ -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 + * + * 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. + */ + +#include "intell_voice_service_proxy.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceServiceProxy" +namespace OHOS { +namespace IntellVoiceEngine { +int32_t IntellVoiceServiceProxy::CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceService::GetDescriptor()); + data.WriteInt32(static_cast(type)); + + Remote()->SendRequest(HDI_INTELL_VOICE_SERVICE_CREATE_ENGINE, data, reply, option); + + sptr remote = reply.ReadRemoteObject(); + if (remote == nullptr) { + INTELL_VOICE_LOG_ERROR("Create engine failed, engine is null"); + return -1; + } + inst = iface_cast(remote); + + return 0; +} + +int32_t IntellVoiceServiceProxy::ReleaseIntellVoiceEngine(IntellVoiceEngineType type) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + + data.WriteInterfaceToken(IIntellVoiceService::GetDescriptor()); + data.WriteInt32(type); + + Remote()->SendRequest(HDI_INTELL_VOICE_SERVICE_RELEASE_ENGINE, data, reply, option); + return reply.ReadInt32(); +} +} +} diff --git a/services/intell_voice_engine/proxy/intell_voice_service_proxy.h b/services/intell_voice_engine/proxy/intell_voice_service_proxy.h new file mode 100755 index 0000000..5b8524e --- /dev/null +++ b/services/intell_voice_engine/proxy/intell_voice_service_proxy.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef INTELL_VOICE_SERVICE_PROXY_H +#define INTELL_VOICE_SERVICE_PROXY_H + +#include +#include "i_intell_voice_service.h" +#include "i_intell_voice_engine.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceServiceProxy : public IRemoteProxy { +public: + explicit IntellVoiceServiceProxy(const sptr &impl) : IRemoteProxy(impl) {} + virtual ~IntellVoiceServiceProxy() {}; + + int32_t CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) override; + int32_t ReleaseIntellVoiceEngine(IntellVoiceEngineType type) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} + +#endif diff --git a/services/intell_voice_engine/server/base/adapter_callback_service.cpp b/services/intell_voice_engine/server/base/adapter_callback_service.cpp new file mode 100755 index 0000000..032c29f --- /dev/null +++ b/services/intell_voice_engine/server/base/adapter_callback_service.cpp @@ -0,0 +1,33 @@ +/* + * 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. + */ +#include "adapter_callback_service.h" +#include "intell_voice_log.h" + +#define LOG_TAG "AdapterCallbackService" + +namespace OHOS { +namespace IntellVoiceEngine { +int32_t AdapterCallbackService::OnIntellVoiceHdiEvent(const IntellVoiceEngineCallBackEvent& event) +{ + if (listener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("listener_ is nullptr"); + return -1; + } + INTELL_VOICE_LOG_INFO("send hdi event"); + listener_->OnIntellVoiceHdiEvent(event); + return 0; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/adapter_callback_service.h b/services/intell_voice_engine/server/base/adapter_callback_service.h new file mode 100755 index 0000000..e7c14e1 --- /dev/null +++ b/services/intell_voice_engine/server/base/adapter_callback_service.h @@ -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 + * + * 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. + */ +#ifndef ADAPTER_CALLBACK_SERVICE_H +#define ADAPTER_CALLBACK_SERVICE_H + +#include "v1_0/iintell_voice_engine_callback.h" +#include "intell_voice_adapter_listener.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OHOS::HDI::IntelligentVoice::Engine::V1_0::IIntellVoiceEngineCallback; +using OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent; + +class AdapterCallbackService final: public IIntellVoiceEngineCallback { +public: + AdapterCallbackService(std::shared_ptr listener) : listener_(listener) {} + virtual ~AdapterCallbackService() = default; + + int32_t OnIntellVoiceHdiEvent(const IntellVoiceEngineCallBackEvent& event) override; +private: + std::shared_ptr listener_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/audio_source.cpp b/services/intell_voice_engine/server/base/audio_source.cpp new file mode 100755 index 0000000..e1f15ab --- /dev/null +++ b/services/intell_voice_engine/server/base/audio_source.cpp @@ -0,0 +1,182 @@ +/* + * 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. + */ +#include "audio_source.h" + +#include "securec.h" +#include "time_util.h" +#include "intell_voice_log.h" +#include "memory_guard.h" + +using namespace OHOS::AudioStandard; +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "AudioSource" + +namespace OHOS { +namespace IntellVoiceEngine { +static const std::string PCM_DIR = "/data/data/intell_voice/pcm_data/"; + +AudioSource::AudioSource(uint32_t minBufferSize, uint32_t bufferCnt, + std::unique_ptr listener, const OHOS::AudioStandard::AudioCapturerOptions &capturerOptions) + : minBufferSize_(minBufferSize), bufferCnt_(bufferCnt), listener_(std::move(listener)) +{ + capturerOptions_.streamInfo.samplingRate = capturerOptions.streamInfo.samplingRate; + capturerOptions_.streamInfo.encoding = capturerOptions.streamInfo.encoding; + capturerOptions_.streamInfo.format = capturerOptions.streamInfo.format; + capturerOptions_.streamInfo.channels = capturerOptions.streamInfo.channels; + capturerOptions_.capturerInfo.sourceType = capturerOptions.capturerInfo.sourceType; + capturerOptions_.capturerInfo.capturerFlags = capturerOptions.capturerInfo.capturerFlags; + + audioCapturer_ = AudioCapturer::Create(capturerOptions_); + if (audioCapturer_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create audio capturer failed"); + } +} + +AudioSource::~AudioSource() +{ + audioCapturer_ = nullptr; +} + +bool AudioSource::Start() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (audioCapturer_ == nullptr) { + INTELL_VOICE_LOG_ERROR("audioCapturer_ is nullptr"); + return false; + } + + if (listener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("listener_ is nullptr"); + return false; + } + + if (minBufferSize_ == 0) { + INTELL_VOICE_LOG_ERROR("minBufferSize_ is invalid"); + return false; + } + + buffer_ = std::shared_ptr(new uint8_t[minBufferSize_], [](uint8_t *p) { delete[] p; }); + if (buffer_ == nullptr) { + INTELL_VOICE_LOG_ERROR("malloc buffer failed"); + return false; + } + + auto path = PCM_DIR + TimeUtil::GetCurrTime() + ".pcm"; + fileStream_ = std::make_unique(path); + if (fileStream_ == nullptr) { + INTELL_VOICE_LOG_ERROR("open debug record file failed"); + return false; + } + + if (!audioCapturer_->Start()) { + INTELL_VOICE_LOG_ERROR("start audio capturer failed"); + fileStream_->close(); + fileStream_ = nullptr; + return false; + } + + isReading_.store(true); + std::thread t1(std::bind(&AudioSource::ReadThread, this)); + readThread_ = std::move(t1); + return true; +} + +void AudioSource::ReadThread() +{ + uint32_t readCnt = 0; + bool isError = true; + while (isReading_.load()) { + if (readCnt >= bufferCnt_) { + INTELL_VOICE_LOG_INFO("finish reading data"); + isError = false; + break; + } + + if (!Read()) { + INTELL_VOICE_LOG_WARN("failed to read data"); + break; + } + ++readCnt; + } + + if (listener_ != nullptr) { + listener_->bufferEndCb_(isError); + } +} + +bool AudioSource::Read() +{ + size_t bytesRead = 0; + while (bytesRead < minBufferSize_) { + int32_t len = audioCapturer_->Read(*(buffer_.get() + bytesRead), minBufferSize_ - bytesRead, 0); + if (len >= 0) { + bytesRead += static_cast(len); + } else { + INTELL_VOICE_LOG_ERROR("read data error, len is %{public}d", len); + break; + } + } + + if (bytesRead != minBufferSize_) { + INTELL_VOICE_LOG_ERROR("failed to read data, bytesRead is %zu", bytesRead); + return false; + } + + if (fileStream_ != nullptr) { + fileStream_->write(reinterpret_cast(buffer_.get()), minBufferSize_); + } + + if (listener_ != nullptr) { + listener_->readBufferCb_(buffer_.get(), minBufferSize_); + } + return true; +} + +void AudioSource::Stop() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (!isReading_.load()) { + INTELL_VOICE_LOG_INFO("already stop"); + return; + } + + MemoryGuard memoryGuard; + + isReading_.store(false); + readThread_.join(); + + if (fileStream_ != nullptr) { + fileStream_->close(); + fileStream_ = nullptr; + } + + if (audioCapturer_ == nullptr) { + INTELL_VOICE_LOG_ERROR("audioCapturer_ is nullptr"); + return; + } + + if (!audioCapturer_->Stop()) { + INTELL_VOICE_LOG_ERROR("stop audio capturer error"); + } + + if (!audioCapturer_->Release()) { + INTELL_VOICE_LOG_ERROR("release audio capturer error"); + } + + audioCapturer_ = nullptr; + listener_ = nullptr; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/audio_source.h b/services/intell_voice_engine/server/base/audio_source.h new file mode 100755 index 0000000..5a46b30 --- /dev/null +++ b/services/intell_voice_engine/server/base/audio_source.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 + * + * 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. + */ +#ifndef AUDIO_SOURCE_H +#define AUDIO_SOURCE_H + +#include +#include +#include +#include +#include +#include "audio_capturer.h" +#include "audio_info.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OnReadBufferCb = std::function; +using OnBufferEndCb = std::function; + +struct AudioSourceListener { + AudioSourceListener(OnReadBufferCb readBufferCb, OnBufferEndCb bufferEndCb) + : readBufferCb_(readBufferCb), bufferEndCb_(bufferEndCb) {} + OnReadBufferCb readBufferCb_; + OnBufferEndCb bufferEndCb_; +}; + +class AudioSource { +public: + AudioSource(uint32_t minBufferSize, uint32_t bufferCnt, std::unique_ptr listener, + const OHOS::AudioStandard::AudioCapturerOptions &capturerOptions); + ~AudioSource(); + bool Start(); + void Stop(); + +private: + void ReadThread(); + bool Read(); + +private: + uint32_t minBufferSize_ = 0; + uint32_t bufferCnt_ = 0; + std::unique_ptr listener_ = nullptr; + std::atomic isReading_ = false; + std::thread readThread_; + OHOS::AudioStandard::AudioCapturerOptions capturerOptions_; + std::shared_ptr buffer_ = nullptr; + std::unique_ptr fileStream_ = nullptr; + std::unique_ptr audioCapturer_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/engine_base.cpp b/services/intell_voice_engine/server/base/engine_base.cpp new file mode 100755 index 0000000..a4a1293 --- /dev/null +++ b/services/intell_voice_engine/server/base/engine_base.cpp @@ -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 + * + * 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. + */ +#include "engine_base.h" + +#include "intell_voice_log.h" +#include "string_util.h" + +using namespace OHOS::IntellVoiceUtils; +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; +#define LOG_TAG "EngineBase" + +namespace OHOS { +namespace IntellVoiceEngine { +EngineBase::EngineBase() +{ + INTELL_VOICE_LOG_INFO("constructor"); + desc_.adapterType = ADAPTER_TYPE_BUT; +} + +int32_t EngineBase::SetParameter(const std::string &keyValueList) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + return adapter_->SetParameter(keyValueList); +} + +std::string EngineBase::GetParameter(const std::string &key) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return ""; + } + + std::string value; + adapter_->GetParameter(key, value); + return value; +} + +int32_t EngineBase::WriteAudio(const uint8_t *buffer, uint32_t size) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + std::vector audioBuff(&buffer[0], &buffer[size]); + return adapter_->WriteAudio(audioBuff); +} + +int32_t EngineBase::Stop() +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + return adapter_->Stop(); +} + +void EngineBase::SplitStringToKVPair(const std::string &inputStr, std::map &kvpairs) +{ + std::vector paramsList; + StringUtil::Split(inputStr, ";", paramsList); + for (auto &it : paramsList) { + std::string key; + std::string value; + if (StringUtil::SplitLineToPair(it, key, value)) { + kvpairs[key] = value; + INTELL_VOICE_LOG_INFO("key:%{public}s, value:%{public}s", key.c_str(), value.c_str()); + } + } +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/engine_base.h b/services/intell_voice_engine/server/base/engine_base.h new file mode 100755 index 0000000..14041a0 --- /dev/null +++ b/services/intell_voice_engine/server/base/engine_base.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 + * + * 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. + */ +#ifndef ENGINE_BASE_H +#define ENGINE_BASE_H +#include +#include +#include +#include +#include "intell_voice_engine_stub.h" +#include "v1_0/iintell_voice_engine_adapter.h" + +namespace OHOS { +namespace IntellVoiceEngine { +enum EngineRelationType { + CONCURRENCY_TYPE, + PREEMPTION_TYPE, + REPLACEMENT_TYPE, +}; + +class EngineBase : public IntellVoiceEngineStub { +public: + ~EngineBase() = default; + virtual bool Init() = 0; + int32_t SetParameter(const std::string &keyValueList) override; + std::string GetParameter(const std::string &key) override; + int32_t WriteAudio(const uint8_t *buffer, uint32_t size) override; + int32_t Stop() override; + virtual void OnDetected() {}; + bool IsRunning() + { + return isRunning_; + } + EngineRelationType GetEngineRelationType() + { + return type_; + } + int32_t GetPriority() + { + return priority_; + } + +protected: + EngineBase(); + void SplitStringToKVPair(const std::string &inputStr, std::map &kvpairs); + std::mutex mutex_; + sptr adapter_ = nullptr; + OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineAdapterDescriptor desc_; + + bool isRunning_ = false; + EngineRelationType type_ = CONCURRENCY_TYPE; + int32_t priority_ = 0; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/engine_factory.cpp b/services/intell_voice_engine/server/base/engine_factory.cpp new file mode 100755 index 0000000..20168bc --- /dev/null +++ b/services/intell_voice_engine/server/base/engine_factory.cpp @@ -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 + * + * 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. + */ + +#include "engine_factory.h" +#include "enroll_engine.h" +#include "wakeup_engine.h" +#include "intell_voice_log.h" +#include "intell_voice_generic_factory.h" + +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "EngineFactory" + +namespace OHOS { +namespace IntellVoiceEngine { +sptr EngineFactory::CreateEngineInst(IntellVoiceEngineType type) +{ + sptr engine = nullptr; + switch (type) { + case INTELL_VOICE_ENROLL: + engine = SptrFactory::CreateInstance(); + break; + case INTELL_VOICE_WAKEUP: + engine = SptrFactory::CreateInstance(); + break; + case INTELL_VOICE_UPDATE: + default: + INTELL_VOICE_LOG_INFO("create engine enter, type:%d", type); + break; + } + + return engine; +} +} +} diff --git a/services/intell_voice_engine/server/base/engine_factory.h b/services/intell_voice_engine/server/base/engine_factory.h new file mode 100755 index 0000000..9e31f44 --- /dev/null +++ b/services/intell_voice_engine/server/base/engine_factory.h @@ -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. + */ +#ifndef ENGINE_FACTORY_H +#define ENGINE_FACTORY_H + +#include "engine_base.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class EngineFactory { +public: + EngineFactory() = default; + ~EngineFactory() = default; + static sptr CreateEngineInst(IntellVoiceEngineType type); +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/file_source.cpp b/services/intell_voice_engine/server/base/file_source.cpp new file mode 100755 index 0000000..a3be822 --- /dev/null +++ b/services/intell_voice_engine/server/base/file_source.cpp @@ -0,0 +1,133 @@ +/* + * 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. + */ +#include "file_source.h" + +#include "securec.h" +#include "intell_voice_log.h" +#include "memory_guard.h" + +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "FileSource" + +namespace OHOS { +namespace IntellVoiceEngine { +FileSource::FileSource(uint32_t minBufferSize, uint32_t bufferCnt, const std::string &filePath, + std::unique_ptr listener) + : minBufferSize_(minBufferSize), bufferCnt_(bufferCnt), filePath_(filePath), listener_(std::move(listener)) +{ +} + +FileSource::~FileSource() +{ + if (isReading_.load()) { + isReading_.store(false); + readThread_.join(); + } +} + +bool FileSource::Start() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (listener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("listener_ is nullptr"); + return false; + } + + if (minBufferSize_ == 0) { + INTELL_VOICE_LOG_ERROR("minBufferSize_ is invalid"); + return false; + } + + buffer_ = std::shared_ptr(new uint8_t[minBufferSize_], [](uint8_t *p) { delete[] p; }); + if (buffer_ == nullptr) { + INTELL_VOICE_LOG_ERROR("malloc buffer failed"); + return false; + } + + fileIn_ = std::make_unique(filePath_, std::ios::binary); + if (fileIn_ == nullptr) { + INTELL_VOICE_LOG_ERROR("open input file failed"); + return false; + } + + fileIn_->seekg(0, fileIn_->end); + uint32_t size = static_cast(fileIn_->tellg()); + if (size < minBufferSize_ * bufferCnt_) { + INTELL_VOICE_LOG_ERROR("file size:%{public}u is smaller than required", size); + fileIn_->close(); + fileIn_ = nullptr; + return false; + } + + isReading_.store(true); + std::thread t1(std::bind(&FileSource::ReadThread, this)); + readThread_ = std::move(t1); + return true; +} + +void FileSource::ReadThread() +{ + uint32_t readCnt = 0; + bool isError = true; + if (fileIn_ == nullptr) { + INTELL_VOICE_LOG_ERROR("fileIn_ is nullptr"); + return; + } + + fileIn_->seekg(0, fileIn_->beg); + + while (isReading_.load()) { + if (readCnt >= bufferCnt_) { + INTELL_VOICE_LOG_INFO("finish reading data"); + isError = false; + break; + } + + if (!(fileIn_->read(reinterpret_cast(buffer_.get()), minBufferSize_))) { + INTELL_VOICE_LOG_ERROR("failed to read file"); + break; + } + + if (listener_ != nullptr) { + listener_->fileBufferCb_(buffer_.get(), minBufferSize_); + } + + ++readCnt; + } + + if (listener_ != nullptr) { + listener_->fileEndCb_(isError); + } +} + +void FileSource::Stop() +{ + INTELL_VOICE_LOG_INFO("enter"); + MemoryGuard memoryGuard; + if (isReading_.load()) { + isReading_.store(false); + readThread_.join(); + } + + if (fileIn_ != nullptr) { + fileIn_->close(); + fileIn_ = nullptr; + } + + buffer_ = nullptr; + listener_ = nullptr; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/file_source.h b/services/intell_voice_engine/server/base/file_source.h new file mode 100755 index 0000000..bbf1ed1 --- /dev/null +++ b/services/intell_voice_engine/server/base/file_source.h @@ -0,0 +1,61 @@ +/* + * 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. + */ +#ifndef FILE_SOURCE_H +#define FILE_SOURCE_H + +#include +#include +#include +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceEngine { +using OnFileBufferCb = std::function; +using OnFileEndCb = std::function; + +struct FileSourceListener { + FileSourceListener(OnFileBufferCb fileBufferCb, OnFileEndCb fileEndCb) + : fileBufferCb_(fileBufferCb), fileEndCb_(fileEndCb) {} + OnFileBufferCb fileBufferCb_; + OnFileEndCb fileEndCb_; +}; + +class FileSource { +public: + FileSource(uint32_t minBufferSize, uint32_t bufferCnt, const std::string &filePath, + std::unique_ptr listener); + ~FileSource(); + bool Start(); + void Stop(); + +private: + void ReadThread(); + bool Read(); + +private: + uint32_t minBufferSize_ = 0; + uint32_t bufferCnt_ = 0; + std::string filePath_; + std::unique_ptr listener_ = nullptr; + std::atomic isReading_ = false; + std::thread readThread_; + std::unique_ptr fileIn_ = nullptr; + std::shared_ptr buffer_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/base/intell_voice_adapter_listener.h b/services/intell_voice_engine/server/base/intell_voice_adapter_listener.h new file mode 100755 index 0000000..c47640f --- /dev/null +++ b/services/intell_voice_engine/server/base/intell_voice_adapter_listener.h @@ -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. + */ +#ifndef INTELL_VOICE_ADAPTER_LISTENER_H +#define INTELL_VOICE_ADAPTER_LISTENER_H + +#include "v1_0/intell_voice_engine_types.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceAdapterListener { +public: + virtual ~IntellVoiceAdapterListener() = default; + virtual void OnIntellVoiceHdiEvent( + const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event) = 0; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/enroll/enroll_adapter_listener.cpp b/services/intell_voice_engine/server/enroll/enroll_adapter_listener.cpp new file mode 100755 index 0000000..0da3456 --- /dev/null +++ b/services/intell_voice_engine/server/enroll/enroll_adapter_listener.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 + * + * 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. + */ +#include "enroll_adapter_listener.h" + +#include +#include "intell_voice_log.h" + +#define LOG_TAG "EnrollAdapterListener" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; + +namespace OHOS { +namespace IntellVoiceEngine { +EnrollAdapterListener::EnrollAdapterListener(const sptr &cb, + OnEnrollEventCb enrollEventCb) : cb_(cb), enrollEventCb_(enrollEventCb) +{ + INTELL_VOICE_LOG_INFO("constructor"); +} + +EnrollAdapterListener::~EnrollAdapterListener() +{ + INTELL_VOICE_LOG_INFO("destructor"); +} + +void EnrollAdapterListener::OnIntellVoiceHdiEvent(const IntellVoiceEngineCallBackEvent& event) +{ + INTELL_VOICE_LOG_INFO("OnIntellVoiceHdiEvent"); + + enrollEventCb_(event.msgId, event.result); + + if (cb_ != nullptr) { + cb_->OnIntellVoiceEngineEvent(event); + } +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/enroll/enroll_adapter_listener.h b/services/intell_voice_engine/server/enroll/enroll_adapter_listener.h new file mode 100755 index 0000000..5ba7940 --- /dev/null +++ b/services/intell_voice_engine/server/enroll/enroll_adapter_listener.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 + * + * 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. + */ +#ifndef ENROLL_ADAPTER_LISTENER_H +#define ENROLL_ADAPTER_LISTENER_H + +#include +#include "intell_voice_adapter_listener.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OnEnrollEventCb = std::function; + +class EnrollAdapterListener : public IntellVoiceAdapterListener { +public: + EnrollAdapterListener(const sptr &cb, OnEnrollEventCb enrollEventCb); + ~EnrollAdapterListener(); + + void OnIntellVoiceHdiEvent( + const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent& event) override; + +private: + sptr cb_ = nullptr; + OnEnrollEventCb enrollEventCb_; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/enroll/enroll_engine.cpp b/services/intell_voice_engine/server/enroll/enroll_engine.cpp new file mode 100755 index 0000000..0483a18 --- /dev/null +++ b/services/intell_voice_engine/server/enroll/enroll_engine.cpp @@ -0,0 +1,377 @@ +/* + * 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. + */ +#include "enroll_engine.h" +#include +#include "securec.h" +#include "intell_voice_log.h" + +#include "v1_0/iintell_voice_engine_manager.h" +#include "v1_0/iintell_voice_engine_callback.h" + +#include "enroll_adapter_listener.h" +#include "time_util.h" +#include "scope_guard.h" +#include "trigger_manager.h" +#include "adapter_callback_service.h" +#include "intell_voice_service_manager.h" + +#define LOG_TAG "EnrollEngine" + +using namespace OHOS::IntellVoiceTrigger; +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; +using namespace OHOS::IntellVoiceUtils; +using namespace OHOS::AudioStandard; + +namespace OHOS { +namespace IntellVoiceEngine { +static constexpr uint32_t MIN_BUFFER_SIZE = 1280; // 16 * 2 * 40ms +static constexpr uint32_t INTERVAL = 125; // 125 * 40ms = 5s +EnrollEngine::EnrollEngine() +{ + INTELL_VOICE_LOG_INFO("enter"); + + capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000; + capturerOptions_.streamInfo.encoding = AudioEncodingType::ENCODING_PCM; + capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE; + capturerOptions_.streamInfo.channels = AudioChannel::MONO; + capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_MIC; + capturerOptions_.capturerInfo.capturerFlags = 0; +} + +EnrollEngine::~EnrollEngine() +{ + auto mgr = IIntellVoiceEngineManager::Get(); + if (mgr != nullptr) { + mgr->ReleaseAdapter(desc_); + } + adapter_ = nullptr; + callback_ = nullptr; + if (audioSource_ != nullptr) { + audioSource_->Stop(); + audioSource_ = nullptr; + } +} + +void EnrollEngine::OnEnrollEvent(int32_t msgId, int32_t result) +{ + if (msgId == INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE) { + std::thread(&EnrollEngine::OnEnrollComplete, this).detach(); + } else if (msgId == INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE) { + std::lock_guard lock(mutex_); + enrollResult_ = result; + } else { + } +} + +void EnrollEngine::OnEnrollComplete() +{ + StopAudioSource(); +} + +bool EnrollEngine::Init() +{ + desc_.adapterType = ENROLL_ADAPTER_TYPE; + auto mgr = IIntellVoiceEngineManager::Get(); + if (mgr == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get engine manager"); + return false; + } + + mgr->CreateAdapter(desc_, adapter_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return false; + } + + return true; +} + +void EnrollEngine::SetCallback(sptr object) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return; + } + + sptr callback = iface_cast(object); + if (callback == nullptr) { + INTELL_VOICE_LOG_ERROR("callback is nullptr"); + return; + } + + std::shared_ptr listener = std::make_shared(callback, + std::bind(&EnrollEngine::OnEnrollEvent, this, std::placeholders::_1, std::placeholders::_2)); + if (listener == nullptr) { + INTELL_VOICE_LOG_ERROR("listener is nullptr"); + return; + } + + callback_ = sptr(new (std::nothrow) AdapterCallbackService(listener)); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + return; + } + + adapter_->SetCallback(callback_); +} + +int32_t EnrollEngine::Attach(const IntellVoiceEngineInfo &info) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("attach"); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + + isPcmFromExternal_ = info.isPcmFromExternal; + + IntellVoiceEngineAdapterInfo adapterInfo = { + .wakeupPhrase = info.wakeupPhrase, + .minBufSize = info.minBufSize, + .sampleChannels = info.sampleChannels, + .bitsPerSample = info.bitsPerSample, + .sampleRate = info.sampleRate, + }; + return adapter_->Attach(adapterInfo); +} + +int32_t EnrollEngine::Detach(void) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + + if (enrollResult_ == 0) { + ProcDspModel(); + } + return adapter_->Detach(); +} + +int32_t EnrollEngine::Start(bool isLast) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("enter"); + if (audioSource_ != nullptr) { + INTELL_VOICE_LOG_ERROR("audioSource_ existed, wait for last start to finish"); + return -1; + } + + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + + if (IntellVoiceServiceManager::GetInstance()->ApplyArbitration(INTELL_VOICE_ENROLL, ENGINE_EVENT_START) != + ARBITRATION_OK) { + INTELL_VOICE_LOG_ERROR("policy manager reject to start engine"); + return 0; + } + + StartInfo info = { + .isLast = isLast, + }; + if (adapter_->Start(info)) { + INTELL_VOICE_LOG_ERROR("start adapter failed"); + return -1; + } + + if (isPcmFromExternal_) { + INTELL_VOICE_LOG_INFO("pcm is from external"); + return 0; + } + + if (!StartAudioSource()) { + INTELL_VOICE_LOG_ERROR("start audio source failed"); + adapter_->Stop(); + return -1; + } + + INTELL_VOICE_LOG_INFO("exit"); + return 0; +} + +int32_t EnrollEngine::Stop() +{ + StopAudioSource(); + + return EngineBase::Stop(); +} + +int32_t EnrollEngine::SetParameter(const std::string &keyValueList) +{ + if (SetParameterInner(keyValueList)) { + INTELL_VOICE_LOG_INFO("inner parameter"); + return 0; + } + + return EngineBase::SetParameter(keyValueList); +} + +bool EnrollEngine::SetParameterInner(const std::string &keyValueList) +{ + std::lock_guard lock(mutex_); + + const std::unique_ptr &historyInfoMgr = + IntellVoiceServiceManager::GetInstance()->GetHistoryInfoMgr(); + if (historyInfoMgr == nullptr) { + INTELL_VOICE_LOG_ERROR("historyInfoMgr is nullptr"); + return false; + } + + std::map kvpairs; + SplitStringToKVPair(keyValueList, kvpairs); + for (auto it : kvpairs) { + if (it.first == std::string("wakeup_bundle_name")) { + INTELL_VOICE_LOG_INFO("set wakeup bundle name:%{public}s", it.second.c_str()); + historyInfoMgr->SetWakeupEngineBundleName(it.second); + return true; + } + if (it.first == std::string("wakeup_ability_name")) { + INTELL_VOICE_LOG_INFO("set wakeup ability name:%{public}s", it.second.c_str()); + historyInfoMgr->SetWakeupEngineAbilityName(it.second); + return true; + } + } + + return false; +} + +void EnrollEngine::WriteBufferFromAshmem(uint8_t *&buffer, uint32_t size, sptr ashmem) +{ + if (!ashmem->MapReadOnlyAshmem()) { + INTELL_VOICE_LOG_ERROR("map ashmem failed"); + return; + } + + const uint8_t *tmpBuffer = static_cast(ashmem->ReadFromAshmem(size, 0)); + if (tmpBuffer == nullptr) { + INTELL_VOICE_LOG_ERROR("read from ashmem failed"); + return; + } + + buffer = new (std::nothrow) uint8_t[size]; + if (buffer == nullptr) { + INTELL_VOICE_LOG_ERROR("allocate buffer failed"); + return; + } + + if (memcpy_s(buffer, size, tmpBuffer, size) != 0) { + INTELL_VOICE_LOG_ERROR("memcpy_s failed"); + return; + } +} + +void EnrollEngine::ProcDspModel() +{ + uint8_t *buffer = nullptr; + uint32_t size = 0; + sptr ashmem; + adapter_->Read(DSP_MODLE, ashmem); + if (ashmem == nullptr) { + INTELL_VOICE_LOG_ERROR("ashmem is nullptr"); + return; + } + + ON_SCOPE_EXIT_WITH_NAME(ashmemExit) + { + INTELL_VOICE_LOG_DEBUG("close ashmem"); + ashmem->UnmapAshmem(); + ashmem->CloseAshmem(); + }; + + size = static_cast(ashmem->GetAshmemSize()); + if (size == 0) { + INTELL_VOICE_LOG_ERROR("size is zero"); + return; + } + + WriteBufferFromAshmem(buffer, size, ashmem); + if (buffer == nullptr) { + INTELL_VOICE_LOG_ERROR("buffer is nullptr"); + return; + } + + ON_SCOPE_EXIT_WITH_NAME(bufferExit) + { + INTELL_VOICE_LOG_DEBUG("now delete buffer"); + delete[] buffer; + buffer = nullptr; + }; + + std::shared_ptr model = std::make_shared( + (IntellVoiceServiceManager::GetEnrollModelUuid()), 1); + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("model is null"); + return; + } + + model->SetData(buffer, size); + auto triggerMgr = TriggerManager::GetInstance(); + if (triggerMgr == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger manager is nullptr"); + return; + } + triggerMgr->UpdateModel(model); +} + +bool EnrollEngine::StartAudioSource() +{ + auto listener = std::make_unique([&] (uint8_t *buffer, uint32_t size) { + if (adapter_ != nullptr) { + std::vector audioBuff(&buffer[0], &buffer[size]); + adapter_->WriteAudio(audioBuff); + }}, [&] (bool isError) + { + INTELL_VOICE_LOG_INFO("end of pcm, isError:%d", isError); + if ((adapter_ != nullptr) && (!isError)) { + adapter_->SetParameter("end_of_pcm=true"); + } + }); + if (listener == nullptr) { + INTELL_VOICE_LOG_ERROR("create listener failed"); + return false; + } + + audioSource_ = std::make_unique(MIN_BUFFER_SIZE, INTERVAL, std::move(listener), + capturerOptions_); + if (audioSource_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create audio source failed"); + return false; + } + + if (!audioSource_->Start()) { + INTELL_VOICE_LOG_ERROR("start capturer failed"); + audioSource_ = nullptr; + return false; + } + + return true; +} + +void EnrollEngine::StopAudioSource() +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("enter"); + if (audioSource_ != nullptr) { + audioSource_->Stop(); + audioSource_ = nullptr; + } +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/enroll/enroll_engine.h b/services/intell_voice_engine/server/enroll/enroll_engine.h new file mode 100755 index 0000000..4d6f999 --- /dev/null +++ b/services/intell_voice_engine/server/enroll/enroll_engine.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 + * + * 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. + */ +#ifndef ENROLL_ENGINE_H +#define ENROLL_ENGINE_H +#include +#include +#include +#include "engine_base.h" +#include "v1_0/iintell_voice_engine_callback.h" +#include "audio_info.h" +#include "audio_source.h" +#include "intell_voice_generic_factory.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class EnrollEngine : public EngineBase { +public: + ~EnrollEngine(); + virtual bool Init() override; + void SetCallback(sptr object) override; + int32_t Attach(const IntellVoiceEngineInfo &info) override; + int32_t Detach(void) override; + int32_t Start(bool isLast) override; + int32_t Stop() override; + int32_t SetParameter(const std::string &keyValueList) override; + +private: + EnrollEngine(); + bool SetParameterInner(const std::string &keyValueList); + bool StartAudioSource(); + void StopAudioSource(); + void OnEnrollEvent(int32_t msgId, int32_t result); + void OnEnrollComplete(); + void ProcDspModel(); + void WriteBufferFromAshmem(uint8_t *&buffer, uint32_t size, sptr ashmem); + +private: + std::string name_ = "lp enroll engine instance"; + bool isPcmFromExternal_ = false; + int32_t enrollResult_ = -1; + sptr callback_ = nullptr; + OHOS::AudioStandard::AudioCapturerOptions capturerOptions_; + std::unique_ptr audioSource_ = nullptr; + friend class IntellVoiceUtils::SptrFactory; +}; +} +} +#endif diff --git a/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.cpp b/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.cpp new file mode 100755 index 0000000..56c109c --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.cpp @@ -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. + */ + +#include "intell_voice_engine_callback_proxy.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceEngineCallbackProxy" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; + +namespace OHOS { +namespace IntellVoiceEngine { +void IntellVoiceEngineCallbackProxy::OnIntellVoiceEngineEvent(const IntellVoiceEngineCallBackEvent &event) +{ + MessageParcel data; + MessageParcel reply; + MessageOption option; + INTELL_VOICE_LOG_INFO("enter"); + + if (!data.WriteInterfaceToken(IIntelligentVoiceEngineCallback::GetDescriptor())) { + INTELL_VOICE_LOG_ERROR("WriteInterfaceToken failed"); + return; + } + + if (!data.WriteInt32(static_cast(event.msgId))) { + INTELL_VOICE_LOG_ERROR("write msgid failed"); + return; + } + + if (!data.WriteInt32(static_cast(event.result))) { + INTELL_VOICE_LOG_ERROR("write result failed"); + return; + } + + if (!data.WriteString(event.info)) { + INTELL_VOICE_LOG_ERROR("write info failed"); + return; + } + + int32_t error = Remote()->SendRequest(IIntelligentVoiceEngineCallback::Code::ON_INTELL_VOICE_ENGINE_EVENT, + data, reply, option); + if (error != 0) { + INTELL_VOICE_LOG_ERROR("send request error: %{public}d", error); + } + reply.ReadInt32(); +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.h b/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.h new file mode 100755 index 0000000..c0eddbc --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_engine_callback_proxy.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 + * + * 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. + */ +#ifndef ENGINE_CALLBACK_PROXY_H +#define ENGINE_CALLBACK_PROXY_H + +#include "iremote_proxy.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent; + +class IntellVoiceEngineCallbackProxy : public IRemoteProxy { +public: + explicit IntellVoiceEngineCallbackProxy(const sptr &impl) + : IRemoteProxy(impl) {}; + virtual ~IntellVoiceEngineCallbackProxy() = default; + void OnIntellVoiceEngineEvent(const IntellVoiceEngineCallBackEvent &event) override; +private: + static inline BrokerDelegator delegator_; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/sa/intell_voice_engine_stub.cpp b/services/intell_voice_engine/server/sa/intell_voice_engine_stub.cpp new file mode 100755 index 0000000..d03f089 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_engine_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 + * + * 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. + */ + +#include "intell_voice_engine_stub.h" +#include "securec.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceEngineStub" + +namespace OHOS { +namespace IntellVoiceEngine { +int32_t IntellVoiceEngineStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + if (data.ReadInterfaceToken() != IIntellVoiceEngine::GetDescriptor()) { + INTELL_VOICE_LOG_ERROR("token mismatch"); + return -1; + } + + int32_t ret = 0; + + switch (code) { + case INTELL_VOICE_ENGINE_SET_CALLBACK: + object = data.ReadRemoteObject(); + SetCallback(object); + break; + case INTELL_VOICE_ENGINE_ATTACH: + info.wakeupPhrase = data.ReadString(); + info.isPcmFromExternal = data.ReadBool(); + info.minBufSize = data.ReadInt32(); + info.sampleChannels = data.ReadInt32(); + info.bitsPerSample = data.ReadInt32(); + info.sampleRate = data.ReadInt32(); + ret = Attach(info); + break; + case INTELL_VOICE_ENGINE_DETACH: + ret = Detach(); + break; + case INTELL_VOICE_ENGINE_SET_PARAMETER: + ret = SetParameter(data.ReadString()); + break; + case INTELL_VOICE_ENGINE_GET_PARAMETER: + str = GetParameter(data.ReadString()); + reply.WriteString(str); + break; + case INTELL_VOICE_ENGINE_START: + ret = Start(data.ReadBool()); + break; + case INTELL_VOICE_ENGINE_STOP: + ret = Stop(); + break; + case INTELL_VOICE_ENGINE_WRITE_AUDIO: + size = data.ReadInt32(); + buffer = data.ReadBuffer(size); + ret = WriteAudio(buffer, size); + break; + default: + ret = IPCObjectStub::OnRemoteRequest(code, data, reply, option); + break; + } + + return ret; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/sa/intell_voice_engine_stub.h b/services/intell_voice_engine/server/sa/intell_voice_engine_stub.h new file mode 100755 index 0000000..be9e3e0 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_engine_stub.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 + * + * 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. + */ + +#ifndef INTELL_VOICE_ENGINE_STUB_H +#define INTELL_VOICE_ENGINE_STUB_H +#include "iremote_stub.h" +#include "i_intell_voice_engine.h" +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceEngineStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +private: + sptr object; + IntellVoiceEngineInfo info; + std::string str; + int size = 0; + const uint8_t *buffer; +}; +} +} +#endif diff --git a/services/intell_voice_engine/server/sa/intell_voice_service.cpp b/services/intell_voice_engine/server/sa/intell_voice_service.cpp new file mode 100755 index 0000000..ff8fcda --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service.cpp @@ -0,0 +1,205 @@ +/* + * 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. + */ +#include "intell_voice_service.h" + +#include +#include +#include +#include +#include "accesstoken_kit.h" +#include "ipc_skeleton.h" +#include "intell_voice_log.h" +#include "system_ability_definition.h" +#include "intell_voice_service_manager.h" +#include "common_event_manager.h" +#include "common_event_support.h" + +using namespace std; +using namespace OHOS::AppExecFwk; +using namespace OHOS::EventFwk; +#define LOG_TAG "IntellVoiceService" + +namespace OHOS { +namespace IntellVoiceEngine { +REGISTER_SYSTEM_ABILITY_BY_ID(IntellVoiceService, INTELL_VOICE_SERVICE_ID, true); +const std::string OHOS_PERMISSION_INTELL_VOICE = "ohos.permission.MANAGE_INTELLIGENT_VOICE"; + +IntellVoiceService::IntellVoiceService(int32_t systemAbilityId, bool runOnCreate) + : SystemAbility(INTELL_VOICE_SERVICE_ID, true) +{ +} + +IntellVoiceService::~IntellVoiceService() +{ +} + +int32_t IntellVoiceService::CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) +{ + if (!VerifyClientPermission(OHOS_PERMISSION_INTELL_VOICE)) { + INTELL_VOICE_LOG_WARN("verify permission"); + } + + INTELL_VOICE_LOG_INFO("enter, type: %{public}d", type); + std::unique_ptr &mgr = IntellVoiceServiceManager::GetInstance(); + if (mgr == nullptr) { + INTELL_VOICE_LOG_ERROR("mgr is nullptr"); + return -1; + } + + inst = mgr->CreateEngine(type); + if (inst == nullptr) { + INTELL_VOICE_LOG_ERROR("engine is nullptr"); + return -1; + } + INTELL_VOICE_LOG_INFO("create engine ok"); + return 0; +} + +int32_t IntellVoiceService::ReleaseIntellVoiceEngine(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter, type: %{public}d", type); + std::unique_ptr &mgr = IntellVoiceServiceManager::GetInstance(); + if (mgr == nullptr) { + INTELL_VOICE_LOG_ERROR("mgr is nullptr"); + return -1; + } + return mgr->ReleaseEngine(type); +} + +void IntellVoiceService::OnStart(void) +{ + bool ret = Publish(this); + if (!ret) { + INTELL_VOICE_LOG_ERROR("publish failed!"); + return; + } + CreateSystemEventObserver(); + AddSystemAbilityListener(COMMON_EVENT_SERVICE_ID); + AddSystemAbilityListener(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID); + RegisterPermissionCallback(OHOS_PERMISSION_INTELL_VOICE); + INTELL_VOICE_LOG_INFO("publish ok"); +} + +void IntellVoiceService::OnStop(void) +{ + const auto &manager = IntellVoiceServiceManager::GetInstance(); + if (manager != nullptr) { + manager->ReleaseSwitchProvider(); + } + + if (systemEventObserver_ != nullptr) { + systemEventObserver_->Unsubscribe(); + } +} + +void IntellVoiceService::OnAddSystemAbility(int32_t systemAbilityId, const std::string &deviceId) +{ + INTELL_VOICE_LOG_INFO("systemAbilityId:%{public}d", systemAbilityId); + if (systemAbilityId == COMMON_EVENT_SERVICE_ID) { + if (systemEventObserver_ != nullptr) { + systemEventObserver_->Subscribe(); + } + } else if (systemAbilityId == DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID) { + const auto &manager = IntellVoiceServiceManager::GetInstance(); + if (manager != nullptr) { + manager->CreateSwitchProvider(); + } + } else { + INTELL_VOICE_LOG_WARN("unhandled sysabilityId"); + } +} + +void IntellVoiceService::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId) +{} + +void IntellVoiceService::CreateSystemEventObserver() +{ + std::shared_ptr runner = EventRunner::Create("service"); + if (runner == nullptr) { + INTELL_VOICE_LOG_ERROR("runner is null"); + return; + } + + std::shared_ptr handler = std::make_shared(runner); + if (handler == nullptr) { + INTELL_VOICE_LOG_ERROR("handler is null"); + return; + } + + OHOS::EventFwk::MatchingSkills matchingSkills; + matchingSkills.AddEvent(OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_ON); + matchingSkills.AddEvent(OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_OFF); + matchingSkills.AddEvent(OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED); + matchingSkills.AddEvent(OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REPLACED); + matchingSkills.AddEvent(OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED); + OHOS::EventFwk::CommonEventSubscribeInfo subscribeInfo(matchingSkills); + systemEventObserver_ = SystemEventObserver::Create(subscribeInfo); + if (systemEventObserver_ == nullptr) { + INTELL_VOICE_LOG_ERROR("systemEventObserver_ is nullptr"); + return; + } + systemEventObserver_->SetEventHandler(handler); + INTELL_VOICE_LOG_INFO("create system event observer successfully"); +} + +static void print_to_file(void *fp, const char *s) +{ + (void)fputs(s, (FILE *)fp); +} + +int IntellVoiceService::Dump(int fd, const std::vector &args) +{ + FILE* fp = fdopen(fd, "w+"); + if (fp != nullptr) { + malloc_stats_print(print_to_file, fp, ""); + fp = nullptr; + } + return 0; +} + +bool IntellVoiceService::VerifyClientPermission(const std::string &permissionName) +{ + Security::AccessToken::AccessTokenID clientTokenId = IPCSkeleton::GetCallingTokenID(); + INTELL_VOICE_LOG_INFO("clientTokenId:%{public}d", clientTokenId); + int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(clientTokenId, permissionName); + if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) { + INTELL_VOICE_LOG_ERROR("Permission denied!"); + return false; + } + return true; +} + +void IntellVoiceService::RegisterPermissionCallback(const std::string &permissionName) +{ + INTELL_VOICE_LOG_INFO("enter"); + Security::AccessToken::PermStateChangeScope scopeInfo; + scopeInfo.permList = {permissionName}; + auto callbackPtr = std::make_shared(scopeInfo); + int32_t res = Security::AccessToken::AccessTokenKit::RegisterPermStateChangeCallback(callbackPtr); + if (res < 0) { + INTELL_VOICE_LOG_ERROR("fail to call RegisterPermStateChangeCallback."); + } +} + +void IntellVoiceService::PerStateChangeCbCustomizeCallback::PermStateChangeCallback( + Security::AccessToken::PermStateChangeInfo& result) +{ + INTELL_VOICE_LOG_INFO("enter, permStateChangeType: %{public}d", result.permStateChangeType); + if (result.permStateChangeType == 0) { + INTELL_VOICE_LOG_ERROR("The permission is canceled."); + } +} +} // namespace IntellVoiceEngine +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_engine/server/sa/intell_voice_service.h b/services/intell_voice_engine/server/sa/intell_voice_service.h new file mode 100755 index 0000000..ca0b399 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service.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 + * + * 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. + */ +#ifndef INTELL_VOICE_SERVICE_H +#define INTELL_VOICE_SERVICE_H +#include +#include "accesstoken_kit.h" +#include "ipc_skeleton.h" +#include "system_ability.h" +#include "intell_voice_service_stub.h" +#include "i_intell_voice_engine.h" +#include "system_event_observer.h" + +#include "trigger_manager.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceService : public SystemAbility, public IntellVoiceServiceStub { + DECLARE_SYSTEM_ABILITY(IntellVoiceService); +public: + explicit IntellVoiceService(int32_t systemAbilityId, bool runOnCreate = true); + ~IntellVoiceService(); + int32_t CreateIntellVoiceEngine(IntellVoiceEngineType type, sptr &inst) override; + int32_t ReleaseIntellVoiceEngine(IntellVoiceEngineType type) override; + int32_t Dump(int fd, const std::vector &args) override; + + class PerStateChangeCbCustomizeCallback : public Security::AccessToken::PermStateChangeCallbackCustomize { + public: + explicit PerStateChangeCbCustomizeCallback(const Security::AccessToken::PermStateChangeScope &scopeInfo) + : PermStateChangeCallbackCustomize(scopeInfo) {} + ~PerStateChangeCbCustomizeCallback() {} + + void PermStateChangeCallback(Security::AccessToken::PermStateChangeInfo& result) override; + }; + +protected: + void OnStart() override; + void OnStop() override; + void OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId) override; + void OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId) override; +private: + void CreateSystemEventObserver(); + bool VerifyClientPermission(const std::string &permissionName); + void RegisterPermissionCallback(const std::string &permissionName); + +private: + std::shared_ptr systemEventObserver_ = nullptr; +}; +} +} +#endif diff --git a/services/intell_voice_engine/server/sa/intell_voice_service_manager.cpp b/services/intell_voice_engine/server/sa/intell_voice_service_manager.cpp new file mode 100755 index 0000000..2e74d54 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service_manager.cpp @@ -0,0 +1,368 @@ +/* + * 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. + */ +#include "intell_voice_service_manager.h" + +#include "intell_voice_log.h" +#include "engine_factory.h" +#include "wakeup_engine.h" +#include "trigger_manager.h" +#include "intell_voice_generic_factory.h" +#include "trigger_detector_callback.h" +#include "memory_guard.h" + +using namespace OHOS::IntellVoiceTrigger; +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "IntellVoiceServiceManager" + +namespace OHOS { +namespace IntellVoiceEngine { +const int32_t IntellVoiceServiceManager::g_enrollModelUuid = 1; + +std::unique_ptr IntellVoiceServiceManager::g_intellVoiceServiceMgr = + std::unique_ptr(new (std::nothrow) IntellVoiceServiceManager()); + +IntellVoiceServiceManager::IntellVoiceServiceManager() +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + historyInfoMgr_ = std::make_unique(); + if (historyInfoMgr_ == nullptr) { + INTELL_VOICE_LOG_ERROR("historyInfoMgr_ is nullptr"); + } +} + +IntellVoiceServiceManager::~IntellVoiceServiceManager() +{ + engines_.clear(); + switchObserver_ = nullptr; + switchProvider_ = nullptr; +} + +std::unique_ptr &IntellVoiceServiceManager::GetInstance() +{ + return g_intellVoiceServiceMgr; +} + +sptr IntellVoiceServiceManager::CreateEngine(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type); + if (type == INTELL_VOICE_ENROLL) { + StopDetection(); + } + + std::lock_guard lock(engineMutex_); + + if (ApplyArbitration(type, ENGINE_EVENT_CREATE) != ARBITRATION_OK) { + INTELL_VOICE_LOG_ERROR("policy manager reject create engine, type:%{public}d", type); + return nullptr; + } + + return CreateEngineInner(type); +} + +sptr IntellVoiceServiceManager::CreateEngineInner(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("create engine enter, type: %d", type); + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + auto it = engines_.find(type); + if (it != engines_.end() && it->second != nullptr) { + return it->second; + } + + sptr engine = EngineFactory::CreateEngineInst(type); + if (engine == nullptr) { + INTELL_VOICE_LOG_ERROR("create engine failed, type:%{public}d", type); + return nullptr; + } + + engines_[type] = engine; + INTELL_VOICE_LOG_INFO("create engine ok"); + return engine; +} + +int32_t IntellVoiceServiceManager::ReleaseEngine(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter, type:%{public}d", type); + std::lock_guard lock(engineMutex_); + auto ret = ReleaseEngineInner(type); + if (ret != 0) { + return ret; + } + + if (type == INTELL_VOICE_ENROLL) { + auto triggerMgr = TriggerManager::GetInstance(); + if (triggerMgr == nullptr) { + INTELL_VOICE_LOG_WARN("trigger manager is nullptr"); + return 0; + } + auto model = triggerMgr->GetModel(IntellVoiceServiceManager::GetEnrollModelUuid()); + if (model == nullptr) { + INTELL_VOICE_LOG_WARN("no model"); + return 0; + } + + auto wakeupEngine = CreateEngineInner(INTELL_VOICE_WAKEUP); + if (wakeupEngine == nullptr) { + INTELL_VOICE_LOG_WARN("failed to create wakeup engine"); + return 0; + } + CreateDetector(); + if (switchProvider_->QuerySwitchStatus()) { + StartDetection(); + } + } + + return 0; +} + +int32_t IntellVoiceServiceManager::ReleaseEngineInner(IntellVoiceEngineType type) +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + auto it = engines_.find(type); + if (it == engines_.end()) { + INTELL_VOICE_LOG_ERROR("there is no engine(%{public}d) in list", type); + return -1; + } + + it->second = nullptr; + engines_.erase(type); + return 0; +} + +void IntellVoiceServiceManager::CreateSwitchProvider() +{ + switchObserver_ = sptr(new (std::nothrow) SwitchObserver()); + if (switchObserver_ == nullptr) { + INTELL_VOICE_LOG_ERROR("switchObserver_ is nullptr"); + return; + } + + switchObserver_->SetUpdateFunc([]() { + const auto &manager = IntellVoiceServiceManager::GetInstance(); + if (manager != nullptr) { + manager->OnSwitchChange(); + } + }); + + switchProvider_ = UniquePtrFactory::CreateInstance(); + if (switchProvider_ == nullptr) { + INTELL_VOICE_LOG_ERROR("switchProvider_ is nullptr"); + return; + } + + if (switchObserver_ != nullptr) { + switchProvider_->RegisterObserver(switchObserver_); + } +} + +void IntellVoiceServiceManager::ReleaseSwitchProvider() +{ + if (switchProvider_ == nullptr) { + INTELL_VOICE_LOG_ERROR("switchProvider_ is nullptr"); + return; + } + + if (switchObserver_ != nullptr) { + switchProvider_->UnregisterObserver(switchObserver_); + } + + switchProvider_ = nullptr; +} + +void IntellVoiceServiceManager::CreateDetector() +{ + std::lock_guard lock(detectorMutex_); + if (detector_ != nullptr) { + INTELL_VOICE_LOG_INFO("detector is already existed, no need to create"); + return; + } + + std::shared_ptr cb = std::make_shared([&]() { OnDetected(); }); + if (cb == nullptr) { + INTELL_VOICE_LOG_ERROR("cb is nullptr"); + return; + } + + auto triggerMgr = TriggerManager::GetInstance(); + if (triggerMgr == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger manager is nullptr"); + return; + } + + detector_ = triggerMgr->CreateTriggerDetector(1, cb); + if (detector_ == nullptr) { + INTELL_VOICE_LOG_ERROR("detector_ is nullptr"); + return; + } +} + +void IntellVoiceServiceManager::StartDetection() +{ + std::lock_guard lock(detectorMutex_); + if (detector_ == nullptr) { + INTELL_VOICE_LOG_ERROR("detector_ is nullptr"); + return; + } + + detector_->StartRecognition(); +} + +void IntellVoiceServiceManager::StopDetection() +{ + std::lock_guard lock(detectorMutex_); + if (detector_ == nullptr) { + return; + } + + detector_->StopRecognition(); +} + +void IntellVoiceServiceManager::OnDetected() +{ + sptr engine = nullptr; + + { + std::lock_guard lock(engineMutex_); + auto it = engines_.find(INTELL_VOICE_WAKEUP); + if ((it == engines_.end()) || (it->second == nullptr)) { + INTELL_VOICE_LOG_ERROR("wakeup engine is not existed"); + return; + } + + engine = it->second; + } + + engine->OnDetected(); +} + +void IntellVoiceServiceManager::OnUserUnlock() +{ + auto triggerMgr = TriggerManager::GetInstance(); + if (triggerMgr == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger manager is nullptr"); + return; + } + auto model = triggerMgr->GetModel(IntellVoiceServiceManager::GetEnrollModelUuid()); + if (model == nullptr) { + INTELL_VOICE_LOG_INFO("no model"); + return; + } + + { + std::lock_guard lock(engineMutex_); + sptr wakeupEngine = EngineFactory::CreateEngineInst(INTELL_VOICE_WAKEUP); + if (wakeupEngine == nullptr) { + INTELL_VOICE_LOG_ERROR("wakeupEngine is nullptr"); + return; + } + engines_[INTELL_VOICE_WAKEUP] = wakeupEngine; + } + + CreateDetector(); + if (switchProvider_->QuerySwitchStatus()) { + StartDetection(); + } +} + +void IntellVoiceServiceManager::OnSwitchChange() +{ + if (switchProvider_ == nullptr) { + INTELL_VOICE_LOG_ERROR("switchProvider_ is nullptr"); + return; + } + + { + std::lock_guard lock(engineMutex_); + auto it = engines_.find(INTELL_VOICE_ENROLL); + if ((it != engines_.end()) && (it->second != nullptr)) { + INTELL_VOICE_LOG_INFO("enroll engine is existed"); + return; + } + } + + if (switchProvider_->QuerySwitchStatus()) { + INTELL_VOICE_LOG_INFO("switch on"); + StartDetection(); + } else { + INTELL_VOICE_LOG_INFO("switch off"); + StopDetection(); + } +} + +int32_t IntellVoiceServiceManager::ApplyArbitration(IntellVoiceEngineType type, EngineEvent event) +{ + INTELL_VOICE_LOG_INFO("enter"); + switch (event) { + case ENGINE_EVENT_CREATE: + return CreateArbitration(type); + case ENGINE_EVENT_START: + return StartArbitration(type); + default: + INTELL_VOICE_LOG_INFO("unknown engine event:%d", event); + break; + } + return ARBITRATION_OK; +} + +int32_t IntellVoiceServiceManager::CreateArbitration(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (type == INTELL_VOICE_ENROLL) { + auto wakeupEngineIt = engines_.find(INTELL_VOICE_WAKEUP); + if (wakeupEngineIt != engines_.end()) { + HandlePreemption(wakeupEngineIt->second); + } + + auto enrollEngineIt = engines_.find(INTELL_VOICE_ENROLL); + if (enrollEngineIt != engines_.end()) { + HandleReplace(enrollEngineIt->second); + } + } + return ARBITRATION_OK; +} + +int32_t IntellVoiceServiceManager::StartArbitration(IntellVoiceEngineType type) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (type == INTELL_VOICE_WAKEUP) { + auto it = engines_.find(INTELL_VOICE_ENROLL); + if (it != engines_.end()) { + return ARBITRATION_REJECT; + } + } + return ARBITRATION_OK; +} + +void IntellVoiceServiceManager::HandlePreemption(sptr currentEngine) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (currentEngine == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to stop current engine, current engine is null"); + return; + } + currentEngine->Stop(); +} + +void IntellVoiceServiceManager::HandleReplace(sptr currentEngine) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (currentEngine == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to detach current engine, current engine is null"); + return; + } + currentEngine->Detach(); + currentEngine = nullptr; +} +} // namespace IntellVoiceEngine +} // namespace OHOS diff --git a/services/intell_voice_engine/server/sa/intell_voice_service_manager.h b/services/intell_voice_engine/server/sa/intell_voice_service_manager.h new file mode 100755 index 0000000..93ebbe6 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service_manager.h @@ -0,0 +1,87 @@ +/* + * 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. + */ +#ifndef SERVICE_MANAGER_H +#define SERVICE_MANAGER_H +#include +#include +#include "engine_base.h" +#include "trigger_detector.h" +#include "switch_observer.h" +#include "switch_provider.h" +#include "history_info_mgr.h" + +namespace OHOS { +namespace IntellVoiceEngine { +enum EngineEvent { + ENGINE_EVENT_CREATE = 0, + ENGINE_EVENT_START, +}; + +enum ArbitrationResult { + ARBITRATION_OK = 0, + ARBITRATION_REJECT, +}; + +class IntellVoiceServiceManager { +public: + ~IntellVoiceServiceManager(); + static std::unique_ptr &GetInstance(); + static int32_t GetEnrollModelUuid() + { + return g_enrollModelUuid; + } + sptr CreateEngine(IntellVoiceEngineType type); + int32_t ReleaseEngine(IntellVoiceEngineType type); + const std::unique_ptr &GetHistoryInfoMgr() + { + return historyInfoMgr_; + } + void OnUserUnlock(); + void CreateSwitchProvider(); + void ReleaseSwitchProvider(); + void StartDetection(); + void StopDetection(); + + int32_t ApplyArbitration(IntellVoiceEngineType type, EngineEvent event); + +private: + IntellVoiceServiceManager(); + void OnSwitchChange(); + void OnDetected(); + void CreateDetector(); + + int32_t CreateArbitration(IntellVoiceEngineType type); + int32_t StartArbitration(IntellVoiceEngineType type); + void HandlePreemption(sptr currentEngine); + void HandleReplace(sptr currentEngine); + + sptr CreateEngineInner(IntellVoiceEngineType type); + int32_t ReleaseEngineInner(IntellVoiceEngineType type); + +private: + static const int32_t g_enrollModelUuid; + static std::unique_ptr g_intellVoiceServiceMgr; + std::mutex engineMutex_; + std::mutex detectorMutex_; + std::map> engines_; + std::shared_ptr detector_ = nullptr; + sptr switchObserver_ = nullptr; + IntellVoiceUtils::UniqueProductType switchProvider_ = + IntellVoiceUtils::UniqueProductType {nullptr, nullptr}; + std::unique_ptr historyInfoMgr_ = nullptr; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/sa/intell_voice_service_stub.cpp b/services/intell_voice_engine/server/sa/intell_voice_service_stub.cpp new file mode 100755 index 0000000..56ac7e7 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service_stub.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 + * + * 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. + */ + +#include "intell_voice_service_stub.h" +#include "intell_voice_log.h" + +#define LOG_TAG "IntellVoiceServiceStub" + +namespace OHOS { +namespace IntellVoiceEngine { +int32_t IntellVoiceServiceStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + if (data.ReadInterfaceToken() != IIntellVoiceService::GetDescriptor()) { + INTELL_VOICE_LOG_ERROR("token mismatch"); + return -1; + } + + IntellVoiceEngineType type = static_cast(data.ReadInt32()); + int32_t ret = 0; + + sptr engine; + switch (code) { + case HDI_INTELL_VOICE_SERVICE_CREATE_ENGINE: + ret = CreateIntellVoiceEngine(type, engine); + reply.WriteRemoteObject(engine->AsObject()); + return ret; + + case HDI_INTELL_VOICE_SERVICE_RELEASE_ENGINE: + return ReleaseIntellVoiceEngine(type); + default: + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } +} +} +} diff --git a/services/intell_voice_engine/server/sa/intell_voice_service_stub.h b/services/intell_voice_engine/server/sa/intell_voice_service_stub.h new file mode 100755 index 0000000..02471f0 --- /dev/null +++ b/services/intell_voice_engine/server/sa/intell_voice_service_stub.h @@ -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. + */ + +#ifndef INTELL_VOICE_SERVICE_STUB_H +#define INTELL_VOICE_SERVICE_STUB_H +#include "iremote_stub.h" +#include "i_intell_voice_service.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class IntellVoiceServiceStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) override; +}; +} +} +#endif diff --git a/services/intell_voice_engine/server/utils/history_info_mgr.cpp b/services/intell_voice_engine/server/utils/history_info_mgr.cpp new file mode 100755 index 0000000..d36d0a5 --- /dev/null +++ b/services/intell_voice_engine/server/utils/history_info_mgr.cpp @@ -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 + * + * 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. + */ +#include "history_info_mgr.h" + +#include "string_util.h" + +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "HistoryInfoMgr" + +namespace OHOS { +namespace IntellVoiceEngine { +constexpr int decimalNotation = 10; +const std::string KEY_ENROLL_ENGINE_UID = "EnrollEngineUid"; +const std::string KEY_WAKEUP_ENGINE_BUNDLE_NAME = "WakeupEngineBundleName"; +const std::string KEY_WAKEUP_ENGINE_ABILITY_NAME = "WakeupEngineAbilityName"; + +HistoryInfoMgr::HistoryInfoMgr() + : ServiceDbHelper("intell_voice_service_manager", "local_intell_voice_history_mgr_storeId") +{ +} + +void HistoryInfoMgr::SetEnrollEngineUid(int32_t uid) +{ + SetValue(KEY_ENROLL_ENGINE_UID, StringUtil::Int2String(uid)); +} + +int32_t HistoryInfoMgr::GetEnrollEngineUid() +{ + std::string value = GetValue(KEY_ENROLL_ENGINE_UID); + return static_cast(strtol(value.c_str(), nullptr, decimalNotation)); +} + +void HistoryInfoMgr::SetWakeupEngineBundleName(std::string bundleName) +{ + SetValue(KEY_WAKEUP_ENGINE_BUNDLE_NAME, bundleName); +} + +std::string HistoryInfoMgr::GetWakeupEngineBundleName() +{ + return GetValue(KEY_WAKEUP_ENGINE_BUNDLE_NAME); +} + +void HistoryInfoMgr::SetWakeupEngineAbilityName(std::string abilityName) +{ + SetValue(KEY_WAKEUP_ENGINE_ABILITY_NAME, abilityName); +} + +std::string HistoryInfoMgr::GetWakeupEngineAbilityName() +{ + return GetValue(KEY_WAKEUP_ENGINE_ABILITY_NAME); +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/history_info_mgr.h b/services/intell_voice_engine/server/utils/history_info_mgr.h new file mode 100755 index 0000000..83d5a51 --- /dev/null +++ b/services/intell_voice_engine/server/utils/history_info_mgr.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 + * + * 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. + */ +#ifndef HISTORY_INFO_MGR_H +#define HISTORY_INFO_MGR_H + +#include "service_db_helper.h" +#include "nocopyable.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class HistoryInfoMgr : private ServiceDbHelper { +public: + HistoryInfoMgr(); + ~HistoryInfoMgr() = default; + + void SetEnrollEngineUid(int32_t uid); + int32_t GetEnrollEngineUid(); + void SetWakeupEngineBundleName(std::string bundleName); + std::string GetWakeupEngineBundleName(); + void SetWakeupEngineAbilityName(std::string abilityName); + std::string GetWakeupEngineAbilityName(); + +private: + DISALLOW_COPY_AND_MOVE(HistoryInfoMgr); +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/service_db_helper.cpp b/services/intell_voice_engine/server/utils/service_db_helper.cpp new file mode 100755 index 0000000..6dccb5a --- /dev/null +++ b/services/intell_voice_engine/server/utils/service_db_helper.cpp @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#include "service_db_helper.h" +#include "intell_voice_log.h" + +using namespace OHOS::DistributedKv; +#define LOG_TAG "ServiceDbHelper" + +namespace OHOS { +namespace IntellVoiceEngine { +ServiceDbHelper::ServiceDbHelper(const std::string &inAppId, const std::string &inStoreId) +{ + AppId appId = { inAppId }; + StoreId storeId = { inStoreId }; + + Options options = { + .createIfMissing = true, + .encrypt = false, + .autoSync = true, + .securityLevel = SecurityLevel::S1, + .area = Area::EL1, + .kvStoreType = KvStoreType::SINGLE_VERSION, + .baseDir = "/data/service/el1/public/database/" + appId.appId + }; + + INTELL_VOICE_LOG_INFO("inAppId:%{public}s, inStoreId:%{public}s, options.baseDir:%{public}s", + inAppId.c_str(), appId.appId.c_str(), options.baseDir.c_str()); + + DistributedKvDataManager manager; + Status status = manager.GetSingleKvStore(options, appId, storeId, kvStore_); + if (status != Status::SUCCESS) { + INTELL_VOICE_LOG_INFO("GetSingleKvStore failed, status: %{public}d.", status); + } else { + INTELL_VOICE_LOG_INFO("GetSingleKvStore success"); + } +} + +ServiceDbHelper::~ServiceDbHelper() +{ + kvStore_ = nullptr; +} + +void ServiceDbHelper::SetValue(const std::string &key, const std::string &value) +{ + if (kvStore_ == nullptr) { + INTELL_VOICE_LOG_ERROR("kvStore_ is nullptr"); + return; + } + kvStore_->Put(key, value); +} + +std::string ServiceDbHelper::GetValue(const std::string &key) +{ + if (kvStore_ == nullptr) { + INTELL_VOICE_LOG_ERROR("kvStore_ is nullptr"); + return ""; + } + Value value; + kvStore_->Get(key, value); + return value.ToString(); +} +} +} diff --git a/services/intell_voice_engine/server/utils/service_db_helper.h b/services/intell_voice_engine/server/utils/service_db_helper.h new file mode 100755 index 0000000..c84806e --- /dev/null +++ b/services/intell_voice_engine/server/utils/service_db_helper.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 + * + * 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. + */ +#ifndef INTELL_VOICE_SERVICE_DB_HELPER_H +#define INTELL_VOICE_SERVICE_DB_HELPER_H + +#include "distributed_kv_data_manager.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class ServiceDbHelper { +public: + ServiceDbHelper(const std::string &inAppId, const std::string &inStoreId); + ~ServiceDbHelper(); + + void SetValue(const std::string &key, const std::string &value); + std::string GetValue(const std::string &key); + +private: + std::shared_ptr kvStore_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/switch_observer.cpp b/services/intell_voice_engine/server/utils/switch_observer.cpp new file mode 100755 index 0000000..cfcc008 --- /dev/null +++ b/services/intell_voice_engine/server/utils/switch_observer.cpp @@ -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 + * + * 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. + */ +#include "switch_observer.h" +#include "intell_voice_log.h" + +#define LOG_TAG "SwitchObserver" + +namespace OHOS { +namespace IntellVoiceEngine { +void SwitchObserver::OnChange() +{ + INTELL_VOICE_LOG_INFO("OnChange"); + if (update_) { + update_(); + } +} + +void SwitchObserver::SetUpdateFunc(UpdateFunc func) +{ + update_ = func; +} +} // namespace IntellVoice +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/switch_observer.h b/services/intell_voice_engine/server/utils/switch_observer.h new file mode 100755 index 0000000..1f555e8 --- /dev/null +++ b/services/intell_voice_engine/server/utils/switch_observer.h @@ -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 + * + * 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. + */ +#ifndef SWITCH_OBSERVER_H +#define SWITCH_OBSERVER_H + +#include +#include "data_ability_observer_stub.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using UpdateFunc = std::function; + +class SwitchObserver : public AAFwk::DataAbilityObserverStub { +public: + SwitchObserver() = default; + virtual ~SwitchObserver() = default; + void OnChange() override; + void SetUpdateFunc(UpdateFunc func); + +private: + UpdateFunc update_ = nullptr; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/switch_provider.cpp b/services/intell_voice_engine/server/utils/switch_provider.cpp new file mode 100755 index 0000000..f1f9f84 --- /dev/null +++ b/services/intell_voice_engine/server/utils/switch_provider.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 + * + * 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. + */ +#include "switch_provider.h" +#include "intell_voice_log.h" +#include "iservice_registry.h" +#include "system_ability_definition.h" + +using namespace OHOS::IntellVoiceUtils; +#define LOG_TAG "SwitchProvider" + +namespace OHOS { +namespace IntellVoiceEngine { +const std::string SWITCH_URI_PROXY = "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true"; +const std::string SWITCH_KEY = "intell_voice_trigger_enabled"; + +SwitchProvider::SwitchProvider() +{ +} + +SwitchProvider::~SwitchProvider() +{ + helper_ = nullptr; +} + +bool SwitchProvider::Init() +{ + auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (saManager == nullptr) { + INTELL_VOICE_LOG_ERROR("saManager is nullptr"); + return false; + } + auto remoteObj = saManager->GetSystemAbility(INTELL_VOICE_SERVICE_ID); + if (remoteObj == nullptr) { + INTELL_VOICE_LOG_ERROR("remoteObj is nullptr"); + return false; + } + + helper_ = DataShare::DataShareHelper::Creator(remoteObj, SWITCH_URI_PROXY); + if (helper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("helper_ is nullptr"); + return false; + } + + return true; +} + +void SwitchProvider::RegisterObserver(const sptr &observer) +{ + auto uri = AssembleUri(SWITCH_KEY); + helper_->RegisterObserver(uri, observer); +} + +void SwitchProvider::UnregisterObserver(const sptr &observer) +{ + auto uri = AssembleUri(SWITCH_KEY); + helper_->UnregisterObserver(uri, observer); +} + +bool SwitchProvider::QuerySwitchStatus() +{ + std::vector columns = {"VALUE"}; + DataShare::DataSharePredicates predicates; + predicates.EqualTo("KEYWORD", SWITCH_KEY); + auto uri = AssembleUri(SWITCH_KEY); + auto resultSet = helper_->Query(uri, predicates, columns); + if (resultSet == nullptr) { + INTELL_VOICE_LOG_ERROR("helper->Query return nullptr"); + return false; + } + + int32_t count; + resultSet->GetRowCount(count); + if (count == 0) { + INTELL_VOICE_LOG_ERROR("not found value"); + return false; + } + const int32_t INDEX = 0; + resultSet->GoToRow(INDEX); + std::string value; + resultSet->GetString(INDEX, value); + resultSet->Close(); + + if (value == "0") { + return false; + } else if (value == "1") { + return true; + } else { + return false; + } +} + +Uri SwitchProvider::AssembleUri(const std::string& key) +{ + Uri uri(SWITCH_URI_PROXY + "&key=" + key); + return uri; +} +} // namespace IntellVoice +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/switch_provider.h b/services/intell_voice_engine/server/utils/switch_provider.h new file mode 100755 index 0000000..ea0d217 --- /dev/null +++ b/services/intell_voice_engine/server/utils/switch_provider.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 + * + * 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. + */ +#ifndef SWITCH_PROVIDER_H +#define SWITCH_PROVIDER_H + +#include "switch_observer.h" +#include "datashare_helper.h" +#include "intell_voice_generic_factory.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class SwitchProvider { +public: + bool Init(); + void RegisterObserver(const sptr &observer); + void UnregisterObserver(const sptr &observer); + bool QuerySwitchStatus(); + +private: + Uri AssembleUri(const std::string& key); + +private: + SwitchProvider(); + ~SwitchProvider(); + + std::shared_ptr helper_ = nullptr; + friend class IntellVoiceUtils::UniquePtrFactory; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/system_event_observer.cpp b/services/intell_voice_engine/server/utils/system_event_observer.cpp new file mode 100755 index 0000000..d4d3596 --- /dev/null +++ b/services/intell_voice_engine/server/utils/system_event_observer.cpp @@ -0,0 +1,103 @@ +/* + * 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. + */ +#include "system_event_observer.h" +#include "event_handler.h" +#include "common_event_manager.h" +#include "common_event_support.h" +#include "intell_voice_log.h" +#include "intell_voice_service_manager.h" + +using namespace OHOS::AppExecFwk; +using namespace OHOS::EventFwk; +#define LOG_TAG "SystemEventObserver" + +namespace OHOS { +namespace IntellVoiceEngine { +SystemEventObserver::SystemEventObserver(const OHOS::EventFwk::CommonEventSubscribeInfo &subscribeInfo) + : EventFwk::CommonEventSubscriber(subscribeInfo), handler_(nullptr) +{ + INTELL_VOICE_LOG_INFO("SystemEventObserver create"); +} + +SystemEventObserver::~SystemEventObserver() +{ + handler_ = nullptr; +} + +std::shared_ptr SystemEventObserver::Create( + const OHOS::EventFwk::CommonEventSubscribeInfo &subscribeInfo) +{ + return std::shared_ptr(new (std::nothrow) SystemEventObserver(subscribeInfo)); +} + +bool SystemEventObserver::Subscribe() +{ + if (!OHOS::EventFwk::CommonEventManager::SubscribeCommonEvent(GetPtr())) { + INTELL_VOICE_LOG_ERROR("SubscribeCommonEvent occur exception."); + return false; + } + return true; +} + +bool SystemEventObserver::Unsubscribe() +{ + if (!OHOS::EventFwk::CommonEventManager::UnSubscribeCommonEvent(GetPtr())) { + INTELL_VOICE_LOG_ERROR("UnsubscribeCommonEvent occur exception."); + return false; + } + return true; +} + +void SystemEventObserver::SetEventHandler(const std::shared_ptr &handler) +{ + handler_ = handler; +} + +void SystemEventObserver::OnReceiveEvent(const OHOS::EventFwk::CommonEventData &eventData) +{ + INTELL_VOICE_LOG_INFO("enter"); + + const OHOS::AAFwk::Want& want = eventData.GetWant(); + std::string action = want.GetAction(); + if (action.empty()) { + INTELL_VOICE_LOG_ERROR("action is empty"); + return; + } + + if (handler_ == nullptr) { + INTELL_VOICE_LOG_ERROR("handler_ is nullptr"); + return; + } + + INTELL_VOICE_LOG_INFO("action:%{public}s.", action.c_str()); + if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_ON) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_SCREEN_ON"); + } else if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_OFF) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_SCREEN_OFF"); + } else if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REMOVED) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_PACKAGE_REMOVED"); + } else if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_REPLACED) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_PACKAGE_REPLACED"); + } else if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_PACKAGE_DATA_CLEARED) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_PACKAGE_DATA_CLEARED"); + } else if (action == OHOS::EventFwk::CommonEventSupport::COMMON_EVENT_USER_UNLOCKED) { + INTELL_VOICE_LOG_INFO("COMMON_EVENT_USER_UNLOCKED"); + IntellVoiceServiceManager::GetInstance()->OnUserUnlock(); + } else { + INTELL_VOICE_LOG_INFO("unkonw event"); + } +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/utils/system_event_observer.h b/services/intell_voice_engine/server/utils/system_event_observer.h new file mode 100755 index 0000000..7a0c299 --- /dev/null +++ b/services/intell_voice_engine/server/utils/system_event_observer.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef SYSTEM_EVENT_OBSERVER_H +#define SYSTEM_EVENT_OBSERVER_H + +#include +#include "common_event_subscriber.h" +#include "event_handler.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class SystemEventObserver : public OHOS::EventFwk::CommonEventSubscriber, + public std::enable_shared_from_this { +public: + ~SystemEventObserver(); + static std::shared_ptr Create(const OHOS::EventFwk::CommonEventSubscribeInfo &subscribeInfo); + std::shared_ptr GetPtr() + { + return shared_from_this(); + } + void OnReceiveEvent(const OHOS::EventFwk::CommonEventData &eventData) override; + void SetEventHandler(const std::shared_ptr &handler); + bool Subscribe(); + bool Unsubscribe(); + +private: + explicit SystemEventObserver(const OHOS::EventFwk::CommonEventSubscribeInfo &subscribeInfo); + + std::shared_ptr handler_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.cpp b/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.cpp new file mode 100755 index 0000000..a703710 --- /dev/null +++ b/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.cpp @@ -0,0 +1,93 @@ +/* + * 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. + */ +#include "wakeup_adapter_listener.h" + +#include +#include "intell_voice_log.h" + +#define LOG_TAG "WakeupAdapterListener" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; + +namespace OHOS { +namespace IntellVoiceEngine { +WakeupAdapterListener::WakeupAdapterListener(OnWakeupEventCb wakeupEventCb) : wakeupEventCb_(wakeupEventCb) + +{ + INTELL_VOICE_LOG_INFO("constructor"); +} + +WakeupAdapterListener::~WakeupAdapterListener() +{ + INTELL_VOICE_LOG_INFO("destructor"); +} + +void WakeupAdapterListener::SetCallback(const sptr &cb) +{ + std::lock_guard lock(mutex_); + if (cb == nullptr) { + INTELL_VOICE_LOG_ERROR("cb is nullptr"); + return; + } + cb_ = cb; + if (historyEvent_ != nullptr) { + cb_->OnIntellVoiceEngineEvent(*(historyEvent_.get())); + historyEvent_ = nullptr; + } +} + +void WakeupAdapterListener::OnIntellVoiceHdiEvent(const IntellVoiceEngineCallBackEvent &event) +{ + INTELL_VOICE_LOG_INFO("OnIntellVoiceHdiEvent"); + + { + std::lock_guard lock(mutex_); + if (cb_ == nullptr) { + INTELL_VOICE_LOG_WARN("cb_ is nullptr"); + BackupCallBackEvent(event); + wakeupEventCb_(event.msgId, event.result); + return; + } + + historyEvent_ = nullptr; + } + + if (event.msgId == INTELL_VOICE_ENGINE_MSG_RECOGNIZE_COMPLETE) { + cb_->OnIntellVoiceEngineEvent(event); + } + + wakeupEventCb_(event.msgId, event.result); +} + +void WakeupAdapterListener::BackupCallBackEvent(const IntellVoiceEngineCallBackEvent &event) +{ + if (event.msgId != INTELL_VOICE_ENGINE_MSG_RECOGNIZE_COMPLETE) { + return; + } + + INTELL_VOICE_LOG_INFO("Backup CallBackEvent"); + + historyEvent_ = std::make_shared(); + if (historyEvent_ == nullptr) { + INTELL_VOICE_LOG_INFO("historyEvent_ is nullptr"); + return; + } + + historyEvent_->msgId = event.msgId; + historyEvent_->result = event.result; + historyEvent_->info = event.info; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.h b/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.h new file mode 100755 index 0000000..c54ddbb --- /dev/null +++ b/services/intell_voice_engine/server/wakeup/wakeup_adapter_listener.h @@ -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 + * + * 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. + */ +#ifndef WAKEUP_ADAPTER_LISTENER_H +#define WAKEUP_ADAPTER_LISTENER_H + +#include +#include +#include +#include "intell_voice_adapter_listener.h" +#include "i_intell_voice_engine_callback.h" + +namespace OHOS { +namespace IntellVoiceEngine { +using OnWakeupEventCb = std::function; + +class WakeupAdapterListener : public IntellVoiceAdapterListener { +public: + explicit WakeupAdapterListener(OnWakeupEventCb wakeupEventCb); + ~WakeupAdapterListener(); + + void SetCallback(const sptr &cb); + void OnIntellVoiceHdiEvent( + const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event) override; + +private: + void BackupCallBackEvent(const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event); + +private: + std::mutex mutex_; + std::shared_ptr historyEvent_ = nullptr; + sptr cb_ = nullptr; + OnWakeupEventCb wakeupEventCb_ = nullptr; +}; +} // namespace IntellVoice +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_engine/server/wakeup/wakeup_engine.cpp b/services/intell_voice_engine/server/wakeup/wakeup_engine.cpp new file mode 100755 index 0000000..c7e4437 --- /dev/null +++ b/services/intell_voice_engine/server/wakeup/wakeup_engine.cpp @@ -0,0 +1,337 @@ +/* + * 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. + */ +#include "wakeup_engine.h" +#include +#include "securec.h" +#include "intell_voice_log.h" + +#include "v1_0/iintell_voice_engine_manager.h" +#include "v1_0/iintell_voice_engine_callback.h" + +#include "time_util.h" +#include "scope_guard.h" +#include "adapter_callback_service.h" +#include "intell_voice_service_manager.h" +#include "ability_manager_client.h" +#include "memory_guard.h" + +using namespace OHOS::HDI::IntelligentVoice::Engine::V1_0; +using namespace OHOS::IntellVoiceUtils; +using namespace OHOS::AudioStandard; +#define LOG_TAG "WakeupEngine" + +namespace OHOS { +namespace IntellVoiceEngine { +static constexpr uint32_t MIN_BUFFER_SIZE = 1280; +static constexpr uint32_t INTERVAL = 50; +static const std::string RECOGNITION_FILE = "/data/data/recognition.pcm"; + +WakeupEngine::WakeupEngine() +{ + INTELL_VOICE_LOG_INFO("enter"); + + capturerOptions_.streamInfo.channels = AudioChannel::MONO; + capturerOptions_.streamInfo.samplingRate = AudioSamplingRate::SAMPLE_RATE_16000; + capturerOptions_.streamInfo.format = AudioSampleFormat::SAMPLE_S16LE; + capturerOptions_.capturerInfo.sourceType = SourceType::SOURCE_TYPE_MIC; + capturerOptions_.capturerInfo.capturerFlags = 0; +} + +WakeupEngine::~WakeupEngine() +{ + auto mgr = IIntellVoiceEngineManager::Get(); + if (mgr != nullptr) { + mgr->ReleaseAdapter(desc_); + } + adapter_ = nullptr; + callback_ = nullptr; +} + +void WakeupEngine::OnDetected() +{ + INTELL_VOICE_LOG_INFO("on detected"); + StartAbility(); + SetParameter("VprTrdType=0;WakeupScene=0"); + Start(true); +} + +void WakeupEngine::OnWakeupEvent(int32_t msgId, int32_t result) +{ + if (msgId == INTELL_VOICE_ENGINE_MSG_RECOGNIZE_COMPLETE) { + std::thread(&WakeupEngine::OnWakeupRecognition, this).detach(); + } +} + +void WakeupEngine::OnWakeupRecognition() +{ + INTELL_VOICE_LOG_INFO("on wakeup recognition"); + { + std::lock_guard lock(mutex_); + + if (fileSource_ != nullptr) { + fileSource_->Stop(); + fileSource_ = nullptr; + } + } + + const auto &manager = IntellVoiceServiceManager::GetInstance(); + if (manager != nullptr) { + manager->StartDetection(); + } + + Stop(); +} + +bool WakeupEngine::SetCallback() +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return false; + } + + adapterListener_ = std::make_shared( + std::bind(&WakeupEngine::OnWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)); + if (adapterListener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapterListener_ is nullptr"); + return false; + } + + callback_ = sptr(new (std::nothrow) AdapterCallbackService(adapterListener_)); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + return false; + } + + adapter_->SetCallback(callback_); + return true; +} + +bool WakeupEngine::Init() +{ + desc_.adapterType = WAKEUP_ADAPTER_TYPE; + auto mgr = IIntellVoiceEngineManager::Get(); + if (mgr == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get engine manager"); + return false; + } + + mgr->CreateAdapter(desc_, adapter_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return false; + } + + if (!SetCallback()) { + INTELL_VOICE_LOG_ERROR("failed to set callback"); + return false; + } + + IntellVoiceEngineInfo info = { + .wakeupPhrase = "\xE5\xB0\x8F\xE8\x89\xBA\xE5\xB0\x8F\xE8\x89\xBA", + .isPcmFromExternal = false, + .minBufSize = 1280, + .sampleChannels = 1, + .bitsPerSample = 16, + .sampleRate = 16000, + }; + + if (Attach(info) != 0) { + INTELL_VOICE_LOG_ERROR("failed to attach"); + return false; + } + + return true; +} + +void WakeupEngine::SetCallback(sptr object) +{ + std::lock_guard lock(mutex_); + if (adapterListener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter listener is nullptr"); + return; + } + + sptr callback = iface_cast(object); + if (callback == nullptr) { + INTELL_VOICE_LOG_ERROR("callback is nullptr"); + return; + } + + adapterListener_->SetCallback(callback); +} + +int32_t WakeupEngine::Attach(const IntellVoiceEngineInfo &info) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("attach"); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + + isPcmFromExternal_ = info.isPcmFromExternal; + + IntellVoiceEngineAdapterInfo adapterInfo = { + .wakeupPhrase = info.wakeupPhrase, + .minBufSize = info.minBufSize, + .sampleChannels = info.sampleChannels, + .bitsPerSample = info.bitsPerSample, + .sampleRate = info.sampleRate, + }; + return adapter_->Attach(adapterInfo); +} + +int32_t WakeupEngine::Detach(void) +{ + std::lock_guard lock(mutex_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + return adapter_->Detach(); +} + +int32_t WakeupEngine::Start(bool isLast) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("enter"); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return -1; + } + + if (IntellVoiceServiceManager::GetInstance()->ApplyArbitration(INTELL_VOICE_WAKEUP, ENGINE_EVENT_START) != + ARBITRATION_OK) { + INTELL_VOICE_LOG_ERROR("policy manager reject to start engine"); + return 0; + } + + StartInfo info = { + .isLast = isLast, + }; + if (adapter_->Start(info)) { + INTELL_VOICE_LOG_ERROR("start adapter failed"); + return -1; + } + + if (isPcmFromExternal_) { + INTELL_VOICE_LOG_INFO("pcm is from external"); + return 0; + } + + if (!StartFileSource()) { + INTELL_VOICE_LOG_ERROR("start file source failed"); + adapter_->Stop(); + return -1; + } + + INTELL_VOICE_LOG_INFO("exit"); + return 0; +} + +void WakeupEngine::StartAbility() +{ + AAFwk::Want want; + const std::unique_ptr &historyInfoMgr = + IntellVoiceServiceManager::GetInstance()->GetHistoryInfoMgr(); + if (historyInfoMgr == nullptr) { + INTELL_VOICE_LOG_ERROR("historyInfoMgr is nullptr"); + return; + } + + std::string bundleName = historyInfoMgr->GetWakeupEngineBundleName(); + std::string abilityName = historyInfoMgr->GetWakeupEngineAbilityName(); + INTELL_VOICE_LOG_INFO("bundleName:%{public}s, abilityName:%{public}s", bundleName.c_str(), abilityName.c_str()); + want.SetElementName(bundleName, abilityName); + want.SetParam("serviceName", std::string("intell_voice")); + AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want); +} + +int32_t WakeupEngine::SetParameter(const std::string &keyValueList) +{ + if (SetParameterInner(keyValueList)) { + INTELL_VOICE_LOG_INFO("inner parameter"); + return 0; + } + + return EngineBase::SetParameter(keyValueList); +} + +bool WakeupEngine::SetParameterInner(const std::string &keyValueList) +{ + std::lock_guard lock(mutex_); + + const auto &manager = IntellVoiceServiceManager::GetInstance(); + if (manager == nullptr) { + INTELL_VOICE_LOG_ERROR(); + return false; + } + + std::map kvpairs; + SplitStringToKVPair(keyValueList, kvpairs); + for (auto it : kvpairs) { + if (it.first == std::string("start_stream")) { + INTELL_VOICE_LOG_INFO("start stream:%{public}s", it.second.c_str()); + manager->StopDetection(); + return true; + } + if (it.first == std::string("stop_stream")) { + INTELL_VOICE_LOG_INFO("stop stream:%{public}s", it.second.c_str()); + manager->StartDetection(); + return true; + } + } + + return false; +} + +bool WakeupEngine::StartFileSource() +{ + auto listener = std::make_unique( + [&](uint8_t *buffer, uint32_t size) { + if (adapter_ != nullptr) { + std::vector audioBuff(&buffer[0], &buffer[size]); + adapter_->WriteAudio(audioBuff); + } + }, + [&](bool isError) + { + INTELL_VOICE_LOG_INFO("end of pcm, isError:%d", isError); + if (adapter_ != nullptr) { + adapter_->SetParameter("end_of_pcm=true"); + } + }); + if (listener == nullptr) { + INTELL_VOICE_LOG_ERROR("create listener failed"); + return false; + } + + fileSource_ = std::make_unique(MIN_BUFFER_SIZE, INTERVAL, RECOGNITION_FILE, std::move(listener)); + if (fileSource_ == nullptr) { + INTELL_VOICE_LOG_ERROR("create file source failed"); + return false; + } + + if (!fileSource_->Start()) { + INTELL_VOICE_LOG_ERROR("start capturer failed"); + fileSource_ = nullptr; + return false; + } + + return true; +} +} // namespace IntellVoice +} // namespace OHOS diff --git a/services/intell_voice_engine/server/wakeup/wakeup_engine.h b/services/intell_voice_engine/server/wakeup/wakeup_engine.h new file mode 100755 index 0000000..6973a55 --- /dev/null +++ b/services/intell_voice_engine/server/wakeup/wakeup_engine.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 + * + * 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. + */ +#ifndef WAKEUP_ENGINE_H +#define WAKEUP_ENGINE_H +#include +#include +#include "engine_base.h" +#include "intell_voice_engine_stub.h" +#include "wakeup_adapter_listener.h" +#include "v1_0/iintell_voice_engine_callback.h" + +#include "audio_info.h" +#include "file_source.h" +#include "intell_voice_generic_factory.h" + +namespace OHOS { +namespace IntellVoiceEngine { +class WakeupEngine : public EngineBase { +public: + ~WakeupEngine(); + bool Init() override; + void SetCallback(sptr object) override; + int32_t Attach(const IntellVoiceEngineInfo &info) override; + int32_t Detach(void) override; + int32_t Start(bool isLast) override; + int32_t SetParameter(const std::string &keyValueList) override; + + void OnDetected() override; + +private: + WakeupEngine(); + void OnWakeupEvent(int32_t msgId, int32_t result); + + void OnWakeupRecognition(); + bool SetCallback(); + bool StartFileSource(); + void StartAbility(); + bool SetParameterInner(const std::string &keyValueList); + +private: + bool isPcmFromExternal_ = false; + std::shared_ptr adapterListener_ = nullptr; + sptr callback_ = nullptr; + OHOS::AudioStandard::AudioCapturerOptions capturerOptions_; + std::unique_ptr fileSource_ = nullptr; + friend class IntellVoiceUtils::SptrFactory; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_callback.h b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_callback.h new file mode 100755 index 0000000..a759b56 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_callback.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_CONNECTOR_CALLBACK_H +#define I_INTELL_VOICE_TRIGGER_CONNECTOR_CALLBACK_H + +#include "v1_0/intell_voice_trigger_types.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceRecognitionEvent; + +class IIntellVoiceTriggerConnectorCallback { +public: + IIntellVoiceTriggerConnectorCallback() = default; + virtual ~IIntellVoiceTriggerConnectorCallback() = default; + + virtual void OnRecognition(int32_t modelHandle, const struct IntellVoiceRecognitionEvent &event) = 0; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_internal.h b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_internal.h new file mode 100755 index 0000000..9d64f7e --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_internal.h @@ -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 + * + * 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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_H +#define I_INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_H + +#include +#include +#include "trigger_connector_common_type.h" +#include "i_intell_voice_trigger_connector_module.h" +#include "i_intell_voice_trigger_connector_callback.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class IIntellVoiceTriggerConnectorInternal { +public: + IIntellVoiceTriggerConnectorInternal() = default; + virtual ~IIntellVoiceTriggerConnectorInternal() = default; + + virtual std::vector ListModuleDescriptors() = 0; + virtual std::shared_ptr GetModule(const std::string &adapterName, + std::shared_ptr callback) = 0; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_module.h b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_module.h new file mode 100755 index 0000000..3102b98 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/i_intell_voice_trigger_connector_module.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 + * + * 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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_CONNECTOR_MODULE_H +#define I_INTELL_VOICE_TRIGGER_CONNECTOR_MODULE_H + +#include +#include +#include "trigger_base_type.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class IIntellVoiceTriggerConnectorModule { +public: + IIntellVoiceTriggerConnectorModule() = default; + virtual ~IIntellVoiceTriggerConnectorModule() = default; + + virtual int32_t LoadModel(std::shared_ptr model, int32_t &modelHandle) = 0; + virtual int32_t UnloadModel(int32_t modelHandle) = 0; + virtual int32_t Start(int32_t modelHandle) = 0; + virtual int32_t Stop(int32_t modelHandle) = 0; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.cpp b/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.cpp new file mode 100755 index 0000000..4d69e91 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.cpp @@ -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 + * + * 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. + */ +#include "trigger_callback_impl.h" +#include "intell_voice_log.h" + +using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0; + +#define LOG_TAG "TriggerCallbackImpl" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerCallbackImpl::TriggerCallbackImpl(std::shared_ptr listener) + :listener_(listener) +{ +} + +int32_t TriggerCallbackImpl::OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent &event, int32_t cookie) +{ + if (listener_ == nullptr) { + INTELL_VOICE_LOG_ERROR("listener_ is nullptr"); + return -1; + } + + listener_->OnRecognitionHdiEvent(event, cookie); + return 0; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.h b/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.h new file mode 100755 index 0000000..c704451 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_callback_impl.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CALLBACK_IMPL_H +#define INTELL_VOICE_TRIGGER_CALLBACK_IMPL_H + +#include "v1_0/iintell_voice_trigger_callback.h" +#include "i_intell_voice_trigger_adapter_listener.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceRecognitionEvent; +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IIntellVoiceTriggerCallback; + +class TriggerCallbackImpl final : public IIntellVoiceTriggerCallback { +public: + explicit TriggerCallbackImpl(std::shared_ptr listener); + virtual ~TriggerCallbackImpl() = default; + + int32_t OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent &event, int32_t cookie) override; + +private: + std::shared_ptr listener_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector.cpp b/services/intell_voice_trigger/server/connector_mgr/trigger_connector.cpp new file mode 100755 index 0000000..b9cab13 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector.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 + * + * 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. + */ +#ifdef TRIGGER_MANAGER_TEST +#include +#endif + +#include "trigger_connector_internal_impl.h" +#include "intell_voice_log.h" +#include "v1_0/iintell_voice_trigger_manager.h" +#include "scope_guard.h" +#include "trigger_callback_impl.h" +#include "memory_guard.h" + +#define LOG_TAG "TriggerConnector" + +using namespace std; +using namespace OHOS::IntellVoiceUtils; +using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0; + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerConnector::TriggerConnector(const IntellVoiceTriggerAdapterDsecriptor &desc) +{ + desc_.adapterName = desc.adapterName; + auto mgr = IIntellVoiceTriggerManager::Get(); + if (mgr != nullptr) { + mgr->LoadAdapter(desc_, adapter_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to load adapter, adapterName is %{public}s", desc_.adapterName.c_str()); + } + } else { + INTELL_VOICE_LOG_INFO("can not get intell voice trigger manager"); + } +} + +TriggerConnector::~TriggerConnector() +{ + auto mgr = IIntellVoiceTriggerManager::Get(); + if (mgr != nullptr) { + mgr->UnloadAdapter(desc_); + } + adapter_ = nullptr; +} + +std::shared_ptr TriggerConnector::GetModule( + std::shared_ptr callback) +{ + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("adapter is nullptr"); + return nullptr; + } + + if (callback == nullptr) { + INTELL_VOICE_LOG_ERROR("callback is nullptr"); + return nullptr; + } + + std::shared_ptr session = std::make_shared(callback, adapter_); + if (session == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to malloc session"); + return nullptr; + } + activeSessions_.insert(session); + return session; +} + +IntellVoiceTriggerProperties TriggerConnector::GetProperties() +{ + IntellVoiceTriggerProperties properties; + return properties; +} + +void TriggerConnector::OnReceive(const ServiceStatus &status) +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + INTELL_VOICE_LOG_INFO("enter"); + if (status.serviceName != INTELL_VOICE_TRIGGER_SERVICE) { + return; + } + if (adapter_ != nullptr) { + return; + } + auto mgr = IIntellVoiceTriggerManager::Get(); + if (mgr != nullptr) { + mgr->LoadAdapter(desc_, adapter_); + if (adapter_ == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to load adapter, adapterName is %{public}s", desc_.adapterName.c_str()); + } + } else { + INTELL_VOICE_LOG_ERROR("failed to get trigger manager"); + } +} + +TriggerConnector::TriggerSession::TriggerSession( + std::shared_ptr callback, const sptr &adapter) + : callback_(callback), adapter_(adapter) +{ + BaseThread::Start(); +} + +TriggerConnector::TriggerSession::~TriggerSession() +{ + Message msg(MSG_TYPE_QUIT); + SendMsg(msg); + Join(); +} + +int32_t TriggerConnector::TriggerSession::LoadModel( + std::shared_ptr model, int32_t &modelHandle) +{ + std::lock_guard lock(mutex_); + std::shared_ptr loadedModle = Model::Create(this); + if (loadedModle == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to malloc intell voice model"); + return -1; + } + + int32_t result = loadedModle->Load(model, modelHandle); + if (result != 0) { + INTELL_VOICE_LOG_ERROR("failed to load generic trigger model"); + return result; + } + loadedModels_.insert(std::make_pair(modelHandle, loadedModle)); + return result; +} + +int32_t TriggerConnector::TriggerSession::UnloadModel(int32_t modelHandle) +{ + std::lock_guard lock(mutex_); + auto it = loadedModels_.find(modelHandle); + if ((it == loadedModels_.end()) || (it->second == nullptr)) { + INTELL_VOICE_LOG_ERROR("failed to find model"); + return -1; + } + return it->second->Unload(); +} + +int32_t TriggerConnector::TriggerSession::Start(int32_t modelHandle) +{ + std::lock_guard lock(mutex_); + auto it = loadedModels_.find(modelHandle); + if ((it == loadedModels_.end()) || (it->second == nullptr)) { + INTELL_VOICE_LOG_ERROR("failed to find model"); + return -1; + } + return it->second->Start(); +} + +int32_t TriggerConnector::TriggerSession::Stop(int32_t modelHandle) +{ + std::lock_guard lock(mutex_); + auto it = loadedModels_.find(modelHandle); + if ((it == loadedModels_.end()) || (it->second == nullptr)) { + INTELL_VOICE_LOG_ERROR("failed to find model"); + return -1; + } + return it->second->Stop(); +} + +void TriggerConnector::TriggerSession::HandleRecognitionHdiEvent(std::shared_ptr event, + int32_t modelHandle) +{ + Message msg(MSG_TYPE_RECOGNITION_HDI_EVENT); + + msg.obj2 = static_pointer_cast(event); + msg.arg1 = modelHandle; + SendMsg(msg); +} + +void TriggerConnector::TriggerSession::ProcessRecognitionHdiEvent(const Message &message) +{ + int32_t modelHandle = message.arg1; + std::shared_ptr event = + static_pointer_cast(message.obj2); + if (event == nullptr) { + INTELL_VOICE_LOG_ERROR("event is nullptr"); + return; + } + + { + std::lock_guard lock(mutex_); + auto it = loadedModels_.find(modelHandle); + if ((it != loadedModels_.end()) && (it->second != nullptr)) { + INTELL_VOICE_LOG_INFO("receive recognition event"); + } + } + callback_->OnRecognition(modelHandle, *(event.get())); +} + +bool TriggerConnector::TriggerSession::HandleMsg(Message &message) +{ + bool quit = false; + + switch (message.mWhat) { + case MSG_TYPE_RECOGNITION_HDI_EVENT: + ProcessRecognitionHdiEvent(message); + break; + default: + INTELL_VOICE_LOG_WARN("invalid msg id: %{public}d", message.mWhat); + break; + } + + if (message.mWhat == MSG_TYPE_QUIT) { + quit = true; + } + + return quit; +} + +std::shared_ptr TriggerConnector::TriggerSession::Model::Create( + TriggerSession *session) +{ + return std::shared_ptr(new (std::nothrow) Model(session)); +} + +int32_t TriggerConnector::TriggerSession::Model::Load( + std::shared_ptr model, int32_t &modelHandle) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (GetState() != IDLE) { + INTELL_VOICE_LOG_ERROR("model has already loaded"); + return -1; + } + + callback_ = sptr(new (std::nothrow) TriggerCallbackImpl(shared_from_this())); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + return -1; + } + + IntellVoiceTriggerModel triggerModel; + triggerModel.data = CreateAshmemFromModelData(model->GetData()); + if (triggerModel.data == nullptr) { + INTELL_VOICE_LOG_ERROR("data is nullptr"); + return -1; + } + triggerModel.type = static_cast(model->GetType()); + triggerModel.uid = static_cast(model->GetUuid()); + + ON_SCOPE_EXIT { + INTELL_VOICE_LOG_INFO("close ashmem"); + triggerModel.data->UnmapAshmem(); + triggerModel.data->CloseAshmem(); + }; + + int32_t handle; + int32_t ret = session_->GetAdapter()->LoadModel(triggerModel, callback_, 0, handle); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("failed to load model"); + return ret; + } + (void)model; + handle_ = handle; + modelHandle = handle_; + SetState(LOADED); + return ret; +} + +int32_t TriggerConnector::TriggerSession::Model::Start() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (GetState() != LOADED) { + INTELL_VOICE_LOG_ERROR("model has not loaded"); + return -1; + } + + int32_t ret = session_->GetAdapter()->Start(handle_); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("failed to load model"); + return ret; + } + +#ifdef TRIGGER_MANAGER_TEST + std::thread(&TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest, this).detach(); +#endif + + SetState(ACTIVE); + return ret; +} + +int32_t TriggerConnector::TriggerSession::Model::Stop() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (GetState() != ACTIVE) { + INTELL_VOICE_LOG_ERROR("model has not activated"); + return -1; + } + + int32_t ret = session_->GetAdapter()->Stop(handle_); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("failed to load model"); + return ret; + } + + SetState(LOADED); + return ret; +} + +int32_t TriggerConnector::TriggerSession::Model::Unload() +{ + INTELL_VOICE_LOG_INFO("enter"); + if (GetState() == IDLE) { + INTELL_VOICE_LOG_ERROR("model has not loaded"); + return -1; + } + + int32_t ret = session_->GetAdapter()->UnloadModel(handle_); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("failed to load model"); + return ret; + } + + SetState(IDLE); + return ret; +} + +#ifdef TRIGGER_MANAGER_TEST +void TriggerConnector::TriggerSession::Model::TriggerManagerCallbackTest() +{ + INTELL_VOICE_LOG_ERROR("enter"); + IntellVoiceRecognitionEvent recognitionEvent; + recognitionEvent.status = static_cast(0); + recognitionEvent.type = static_cast(1); + recognitionEvent.modelHandle = handle_; + TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(recognitionEvent, 0); +} +#endif + +void TriggerConnector::TriggerSession::Model::OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent& event, + int32_t cookie) +{ + (void)cookie; + std::shared_ptr recognitionEvent = std::make_shared(); + if (recognitionEvent == nullptr) { + INTELL_VOICE_LOG_ERROR("recognitionEvent is nullptr"); + return; + } + + recognitionEvent->status = event.status; + recognitionEvent->type = event.type; + recognitionEvent->modelHandle = event.modelHandle; + + INTELL_VOICE_LOG_INFO("handle: %{public}d", handle_); + session_->HandleRecognitionHdiEvent(recognitionEvent, handle_); +} + +sptr TriggerConnector::TriggerSession::Model::CreateAshmemFromModelData( + const std::vector &modelData) +{ + if (modelData.size() == 0) { + INTELL_VOICE_LOG_ERROR("data is empty"); + return nullptr; + } + + sptr buffer = OHOS::Ashmem::CreateAshmem("ModelData", modelData.size()); + if (buffer == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to create ashmem"); + return nullptr; + } + + if (!buffer->MapReadAndWriteAshmem()) { + INTELL_VOICE_LOG_ERROR("failed to map ashmem"); + goto ERR_EXIT; + } + + if (!buffer->WriteToAshmem(modelData.data(), modelData.size(), 0)) { + INTELL_VOICE_LOG_ERROR("failed to write ashmem"); + goto ERR_EXIT; + } + + INTELL_VOICE_LOG_INFO("model data size:%{public}zu", modelData.size()); + return buffer; + +ERR_EXIT: + buffer->UnmapAshmem(); + buffer->CloseAshmem(); + return nullptr; +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector.h b/services/intell_voice_trigger/server/connector_mgr/trigger_connector.h new file mode 100755 index 0000000..fedc824 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector.h @@ -0,0 +1,135 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CONNECTOR_H +#define INTELL_VOICE_TRIGGER_CONNECTOR_H + +#include +#include +#include +#include +#include +#include +#include "v1_0/iintell_voice_trigger_adapter.h" +#include "i_intell_voice_trigger_adapter_listener.h" +#include "i_intell_voice_trigger_connector_module.h" +#include "i_intell_voice_trigger_connector_callback.h" +#include "msg_handle_thread.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::ServiceManager::V1_0::ServiceStatus; +using OHOS::HDI::ServiceManager::V1_0::ServStatListenerStub; + +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceTriggerAdapterDsecriptor; +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceTriggerProperties; +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IIntellVoiceTriggerAdapter; +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceRecognitionEvent; +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IIntellVoiceTriggerCallback; + +const std::string INTELL_VOICE_TRIGGER_SERVICE = "intell_voice_trigger_manager_service"; + +class TriggerConnector : public ServStatListenerStub { +public: + explicit TriggerConnector(const IntellVoiceTriggerAdapterDsecriptor &desc); + ~TriggerConnector() override; + std::shared_ptr GetModule( + std::shared_ptr callback); + IntellVoiceTriggerProperties GetProperties(); + void OnReceive(const ServiceStatus &status) override; + +private: + class TriggerSession : public IIntellVoiceTriggerConnectorModule, public OHOS::IntellVoiceUtils::MsgHandleThread { + public: + TriggerSession(std::shared_ptr callback, + const sptr &adapter); + ~TriggerSession() override; + const sptr &GetAdapter() + { + return adapter_; + } + std::shared_ptr GetCallback() + { + return callback_; + } + int32_t LoadModel(std::shared_ptr model, int32_t &modelHandle) override; + int32_t UnloadModel(int32_t modelHandle) override; + int32_t Start(int32_t modelHandle) override; + int32_t Stop(int32_t modelHandle) override; + + void HandleRecognitionHdiEvent(std::shared_ptr event, + int32_t modelHandle); + private: + enum MsgType { + MSG_TYPE_NONE, + MSG_TYPE_RECOGNITION_HDI_EVENT, + MSG_TYPE_QUIT, + }; + + private: + class Model : public IIntellVoiceTriggerAdapterListener, public std::enable_shared_from_this { + public: + static std::shared_ptr Create(TriggerSession *session); + int32_t Load(std::shared_ptr model, int32_t &modelHandle); + int32_t Unload(); + int32_t Start(); + int32_t Stop(); +#ifdef TRIGGER_MANAGER_TEST + void TriggerManagerCallbackTest(); +#endif + public: + void OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent &event, int32_t cookie) override; + + enum ModelState { + IDLE, + LOADED, + ACTIVE, + }; + ModelState GetState() + { + return state_.load(); + } + + void SetState(ModelState state) + { + state_.store(state); + } + + private: + explicit Model(TriggerSession *session) : session_(session) {} + sptr CreateAshmemFromModelData(const std::vector &modelData); + int32_t handle_ = 0; + std::atomic state_ = IDLE; + TriggerSession *session_ = nullptr; + sptr callback_ = nullptr; + }; // Model + + private: + bool HandleMsg(OHOS::IntellVoiceUtils::Message &message) override; + void ProcessRecognitionHdiEvent(const OHOS::IntellVoiceUtils::Message &message); + private: + std::mutex mutex_ {}; + std::shared_ptr callback_ = nullptr; + const OHOS::sptr &adapter_; + std::map> loadedModels_; + }; // TriggerSession + +private: + IntellVoiceTriggerAdapterDsecriptor desc_; + sptr adapter_ = nullptr; + std::set> activeSessions_; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_common_type.h b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_common_type.h new file mode 100755 index 0000000..8a4b8c6 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_common_type.h @@ -0,0 +1,31 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CONNECTOR_COMMON_TYPE_H +#define INTELL_VOICE_TRIGGER_CONNECTOR_COMMON_TYPE_H + +#include +#include "v1_0/intell_voice_trigger_types.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceTriggerProperties; + +struct TriggerConnectorModuleDesc { + std::string adapterName; + IntellVoiceTriggerProperties properties; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.cpp b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.cpp new file mode 100755 index 0000000..4c31bee --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.cpp @@ -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 + * + * 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. + */ +#include "trigger_connector_internal_impl.h" +#include +#include +#include "intell_voice_log.h" +#include "v1_0/iintell_voice_trigger_manager.h" +#include "memory_guard.h" + +#define LOG_TAG "TriggerConnectorInternalImpl" + +using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0; + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerConnectorInternalImpl::TriggerConnectorInternalImpl() +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + IntellVoiceTriggerAdapterDsecriptor descriptor; + descriptor.adapterName = "primary"; + + sptr servmgr_ = IServiceManager::Get(); + if (servmgr_ != nullptr) { + auto connector = sptr(new (std::nothrow) TriggerConnector(descriptor)); + if (connector != nullptr) { + servmgr_->RegisterServiceStatusListener(connector, DEVICE_CLASS_DEFAULT); + connectors_[descriptor.adapterName] = connector; + } else { + INTELL_VOICE_LOG_ERROR("failed to malloc connector"); + } + } else { + INTELL_VOICE_LOG_ERROR("failed to get hdf service manager"); + } +} + +TriggerConnectorInternalImpl::~TriggerConnectorInternalImpl() +{ + INTELL_VOICE_LOG_DEBUG("TriggerConnectorInternalImpl destructor"); + for (auto it = connectors_.begin(); it != connectors_.end(); ++it) { + servmgr_->UnregisterServiceStatusListener(it->second); + } +} + +std::vector TriggerConnectorInternalImpl::ListModuleDescriptors() +{ + std::vector ret; + for (auto it = connectors_.begin(); it != connectors_.end(); ++it) { + TriggerConnectorModuleDesc item; + item.adapterName = it->first; + item.properties = it->second->GetProperties(); + ret.emplace_back(item); + } + return ret; +} + +std::shared_ptr TriggerConnectorInternalImpl::GetModule( + const std::string &adapterName, std::shared_ptr callback) +{ + auto it = connectors_.find(adapterName); + if ((it == connectors_.end()) || (it->second == nullptr)) { + INTELL_VOICE_LOG_ERROR("failed to find connector"); + return nullptr; + } + + return it->second->GetModule(callback); +} +} +} diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.h b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.h new file mode 100755 index 0000000..b63a391 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_impl.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_IMPL_H +#define INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_IMPL_H + +#include +#include +#include "i_intell_voice_trigger_connector_internal.h" +#include "trigger_connector.h" + +using OHOS::HDI::ServiceManager::V1_0::IServiceManager; + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerConnectorInternalImpl : public IIntellVoiceTriggerConnectorInternal { +public: + TriggerConnectorInternalImpl(); + ~TriggerConnectorInternalImpl() override; + std::vector ListModuleDescriptors() override; + std::shared_ptr GetModule(const std::string &adapterName, + std::shared_ptr callback) override; + +private: + std::map> connectors_; + sptr servmgr_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.cpp b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.cpp new file mode 100755 index 0000000..80baa53 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.cpp @@ -0,0 +1,137 @@ +/* + * 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. + */ +#include "trigger_connector_internal_validation.h" +#include "intell_voice_log.h" + +#define LOG_TAG "TriggerConnectorInternalValidation" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerConnectorInternalValidation::TriggerConnectorInternalValidation( + std::unique_ptr delegate) : delegate_(std::move(delegate)) +{ +} + +std::vector TriggerConnectorInternalValidation::ListModuleDescriptors() +{ + std::lock_guard lock(mutex_); + std::vector ret = delegate_->ListModuleDescriptors(); + if (ret.empty()) { + INTELL_VOICE_LOG_ERROR("no trigger connector module desc"); + return ret; + } + + if (moduleDescs_.empty()) { + for (auto it : ret) { + moduleDescs_.insert(it.adapterName); + } + } else { + if (ret.size() != moduleDescs_.size()) { + INTELL_VOICE_LOG_ERROR("size different, ret size:%zu, module descs size:%zu", ret.size(), + moduleDescs_.size()); + return {}; + } + + for (auto it : ret) { + if (moduleDescs_.count(it.adapterName) == 0) { + INTELL_VOICE_LOG_ERROR("adapter name:%s does not exist", it.adapterName.c_str()); + return {}; + } + } + } + return ret; +} + +std::shared_ptr TriggerConnectorInternalValidation::GetModule( + const std::string &adapterName, std::shared_ptr callback) +{ + std::lock_guard lock(mutex_); + if (moduleDescs_.count(adapterName) == 0) { + INTELL_VOICE_LOG_ERROR("adapter name:%s does not exist", adapterName.c_str()); + return nullptr; + } + std::shared_ptr moduleValidation = + std::make_shared(callback); + if (moduleValidation == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to malloc connector module validation"); + return nullptr; + } + + auto delegate = delegate_->GetModule(adapterName, moduleValidation->GetCallbackWrapper()); + if (delegate == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get delegate"); + return nullptr; + } + moduleValidation->SetDelegate(delegate); + return moduleValidation; +} + +bool TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::ValidationUtils::ValidateGenericModel( + std::shared_ptr model) +{ + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("generic model is nullptr"); + return false; + } + + if (model->GetType() != TriggerModel::TriggerModelType::GENERIC_TYPE) { + INTELL_VOICE_LOG_ERROR("generic model type:%d is invalid", model->GetType()); + return false; + } + + if (model->GetData().size() == 0) { + INTELL_VOICE_LOG_ERROR("generic model data size is zero"); + return false; + } + + return true; +} + +TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::TriggerConnectorModuleValidation( + std::shared_ptr callback) +{ + callbackWrapper_ = std::make_shared(callback); + if (callbackWrapper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to malloc callback wrapper"); + } +} + +int32_t TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::LoadModel( + std::shared_ptr model, int32_t &modelHandle) +{ + if (!ValidationUtils::ValidateGenericModel(model)) { + INTELL_VOICE_LOG_ERROR(); + return -1; + } + return delegate_->LoadModel(model, modelHandle); +} + +int32_t TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::UnloadModel( + int32_t modelHandle) +{ + return delegate_->UnloadModel(modelHandle); +} + +int32_t TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::Start(int32_t modelHandle) +{ + return delegate_->Start(modelHandle); +} + +int32_t TriggerConnectorInternalValidation::TriggerConnectorModuleValidation::Stop(int32_t modelHandle) +{ + return delegate_->Stop(modelHandle); +} +} +} diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.h b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.h new file mode 100755 index 0000000..e1dd0eb --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_internal_validation.h @@ -0,0 +1,81 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_VALIDATION_H +#define INTELL_VOICE_TRIGGER_CONNECTOR_INTERNAL_VALIDATION_H + +#include +#include +#include +#include "v1_0/intell_voice_trigger_types.h" +#include "i_intell_voice_trigger_connector_internal.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceRecognitionEvent; + +class TriggerConnectorInternalValidation : public IIntellVoiceTriggerConnectorInternal { +public: + explicit TriggerConnectorInternalValidation(std::unique_ptr delegate); + std::vector ListModuleDescriptors() override; + std::shared_ptr GetModule(const std::string &adapterName, + std::shared_ptr callback) override; + +private: + std::mutex mutex_; + std::set moduleDescs_; + std::unique_ptr delegate_ = nullptr; + +private: + class TriggerConnectorModuleValidation : public IIntellVoiceTriggerConnectorModule { + public: + explicit TriggerConnectorModuleValidation(std::shared_ptr callback); + std::shared_ptr GetCallbackWrapper() + { + return callbackWrapper_; + } + void SetDelegate(std::shared_ptr delegate) + { + delegate_ = delegate; + } + int32_t LoadModel(std::shared_ptr model, int32_t &modelHandle) override; + int32_t UnloadModel(int32_t modelHandle) override; + int32_t Start(int32_t modelHandle) override; + int32_t Stop(int32_t modelHandle) override; + + private: + class TriggerConnectorCallbackValidation : public IIntellVoiceTriggerConnectorCallback { + public: + explicit TriggerConnectorCallbackValidation(std::shared_ptr delegate) + : delegate_(delegate) {} + void OnRecognition(int32_t modelHandle, const IntellVoiceRecognitionEvent &event) override + { + delegate_->OnRecognition(modelHandle, event); + } + private: + std::shared_ptr delegate_; + }; + + class ValidationUtils { + public: + static bool ValidateGenericModel(std::shared_ptr model); + }; + private: + std::shared_ptr delegate_ = nullptr; + std::shared_ptr callbackWrapper_ = nullptr; + }; +}; +} +} +#endif diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.cpp b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.cpp new file mode 100755 index 0000000..8ea4479 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.cpp @@ -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 + * + * 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. + */ +#include "trigger_connector_mgr.h" +#include "intell_voice_log.h" +#include "trigger_connector_internal_validation.h" +#include "trigger_connector_internal_impl.h" + +#define LOG_TAG "TriggerConnectorMgr" + +namespace OHOS { +namespace IntellVoiceTrigger { +std::unique_ptr TriggerConnectorMgr::g_connectorMgr = + std::unique_ptr( + new (std::nothrow) TriggerConnectorMgr(std::make_unique( + std::make_unique()))); + +TriggerConnectorMgr::TriggerConnectorMgr(std::unique_ptr delegate) + : delegate_(std::move(delegate)) +{} + +std::unique_ptr &TriggerConnectorMgr::GetInstance() +{ + return g_connectorMgr; +} + +std::vector TriggerConnectorMgr::ListConnectorModuleDescriptors() +{ + if (delegate_ == nullptr) { + INTELL_VOICE_LOG_ERROR("delegate_ is nullptr"); + return {}; + } + + return delegate_->ListModuleDescriptors(); +} + +std::shared_ptr TriggerConnectorMgr::GetConnectorModule( + const std::string &adapterName, std::shared_ptr callback) +{ + if (delegate_ == nullptr) { + INTELL_VOICE_LOG_ERROR("delegate_ is nullptr"); + return nullptr; + } + + return delegate_->GetModule(adapterName, callback); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.h b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.h new file mode 100755 index 0000000..dad2153 --- /dev/null +++ b/services/intell_voice_trigger/server/connector_mgr/trigger_connector_mgr.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_CONNECTOR_MGR_H +#define INTELL_VOICE_TRIGGER_CONNECTOR_MGR_H + +#include "nocopyable.h" +#include "i_intell_voice_trigger_connector_internal.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerConnectorMgr { +public: + ~TriggerConnectorMgr() = default; + static std::unique_ptr &GetInstance(); + std::vector ListConnectorModuleDescriptors(); + std::shared_ptr GetConnectorModule( + const std::string &adapterName, std::shared_ptr callback); + +private: + explicit TriggerConnectorMgr(std::unique_ptr delegate); + +private: + static std::unique_ptr g_connectorMgr; + std::unique_ptr delegate_ = nullptr; + + DISALLOW_COPY(TriggerConnectorMgr); + DISALLOW_MOVE(TriggerConnectorMgr); +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/i_intell_voice_trigger_adapter_listener.h b/services/intell_voice_trigger/server/i_intell_voice_trigger_adapter_listener.h new file mode 100755 index 0000000..ea712f7 --- /dev/null +++ b/services/intell_voice_trigger/server/i_intell_voice_trigger_adapter_listener.h @@ -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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_ADAPTER_LISTENER_H +#define I_INTELL_VOICE_TRIGGER_ADAPTER_LISTENER_H +#include "v1_0/intell_voice_trigger_types.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OHOS::HDI::IntelligentVoice::Trigger::V1_0::IntellVoiceRecognitionEvent; + +class IIntellVoiceTriggerAdapterListener { +public: + virtual ~IIntellVoiceTriggerAdapterListener() = default; + virtual void OnRecognitionHdiEvent(const IntellVoiceRecognitionEvent &event, int32_t cookie) = 0; +}; +} +} +#endif diff --git a/services/intell_voice_trigger/server/i_intell_voice_trigger_detector_callback.h b/services/intell_voice_trigger/server/i_intell_voice_trigger_detector_callback.h new file mode 100755 index 0000000..7ecdee1 --- /dev/null +++ b/services/intell_voice_trigger/server/i_intell_voice_trigger_detector_callback.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 + * + * 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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_DETECTOR_CALLBACK_H +#define I_INTELL_VOICE_TRIGGER_DETECTOR_CALLBACK_H + +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceTrigger { +struct DetectorEvent { + DetectorEvent(int32_t audioFormat, std::vector data) : audioFormat_(audioFormat) + { + data_.swap(data); + } + int32_t audioFormat_ {0}; + std::vector data_; +}; + +class IIntellVoiceTriggerDetectorCallback { +public: + IIntellVoiceTriggerDetectorCallback() = default; + virtual ~IIntellVoiceTriggerDetectorCallback() {}; + + virtual void OnDetected(const std::shared_ptr &event) = 0; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/i_intell_voice_trigger_recognition_callback.h b/services/intell_voice_trigger/server/i_intell_voice_trigger_recognition_callback.h new file mode 100755 index 0000000..ab42864 --- /dev/null +++ b/services/intell_voice_trigger/server/i_intell_voice_trigger_recognition_callback.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 + * + * 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. + */ +#ifndef I_INTELL_VOICE_TRIGGER_RECOGNITION_CALLBACK_H +#define I_INTELL_VOICE_TRIGGER_RECOGNITION_CALLBACK_H + +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceTrigger { +struct GenericTriggerEvent { + int32_t modelHandle_ {0}; + int32_t audioFormat_ {0}; + std::vector data_; +}; + +class IIntellVoiceTriggerRecognitionCallback { +public: + IIntellVoiceTriggerRecognitionCallback() = default; + virtual ~IIntellVoiceTriggerRecognitionCallback() {}; + virtual void OnGenericTriggerDetected(const std::shared_ptr event) = 0; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_base_type.cpp b/services/intell_voice_trigger/server/trigger_base_type.cpp new file mode 100755 index 0000000..ba19130 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_base_type.cpp @@ -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 + * + * 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. + */ +#include "trigger_base_type.h" +#include "securec.h" +#include "intell_voice_log.h" + +#define LOG_TAG "TriggerBaseType" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerModel::TriggerModel(TriggerModelType type, int32_t uuid, int32_t version) + : type_(type), uuid_(uuid), version_(version) +{} + +TriggerModel::~TriggerModel() +{ +} + +bool TriggerModel::SetData(const uint8_t *data, uint32_t size) +{ + if (size <= 0) { + INTELL_VOICE_LOG_ERROR("size is invalid"); + return false; + } + data_.resize(size); + + if (memcpy_s(data_.data(), data_.size(), data, size) != 0) { + INTELL_VOICE_LOG_ERROR("memcpy_s error"); + return false; + } + return true; +} + +bool TriggerModel::SetData(std::vectordata) +{ + if (data.size() <= 0) { + INTELL_VOICE_LOG_ERROR("size is invalid"); + return false; + } + data_.swap(data); + return true; +} + +void TriggerModel::Print() +{ + INTELL_VOICE_LOG_INFO("trigger model type:%{public}d", type_); + INTELL_VOICE_LOG_INFO("trigger model uuid:%{public}d", uuid_); + INTELL_VOICE_LOG_INFO("trigger model vendor uuid:%{public}d", vendorUuid_); + INTELL_VOICE_LOG_INFO("trigger model version:%{public}d", version_); + INTELL_VOICE_LOG_INFO("trigger model data size:%{public}lu", data_.size()); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_base_type.h b/services/intell_voice_trigger/server/trigger_base_type.h new file mode 100755 index 0000000..f2f01d2 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_base_type.h @@ -0,0 +1,84 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_MODEL_H +#define INTELL_VOICE_TRIGGER_MODEL_H + +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerModel { +public: + enum TriggerModelType { + GENERIC_TYPE = 1, + UNKNOWN_TYPE = -1, + }; + + TriggerModel(TriggerModelType type, int32_t uuid, int32_t version); + virtual ~TriggerModel(); + + bool SetData(const uint8_t *data, uint32_t size); + bool SetData(std::vector data); + void Print(); + + int32_t GetUuid() + { + return uuid_; + } + + int32_t GetType() + { + return type_; + } + + int32_t GetVendorUuid() + { + return vendorUuid_; + } + + int32_t GetVersion() + { + return version_; + } + + std::vector GetData() + { + return data_; + } + +protected: + TriggerModelType type_ = UNKNOWN_TYPE; + int32_t uuid_ = -1; + int32_t vendorUuid_ = -1; + int32_t version_ = -1; + +private: + std::vector data_; +}; + +class GenericTriggerModel : public TriggerModel { +public: + GenericTriggerModel(int32_t uuid, int32_t version) + : TriggerModel(TriggerModel::TriggerModelType::GENERIC_TYPE, uuid, version) + {} + ~GenericTriggerModel() override + {} +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_db_helper.cpp b/services/intell_voice_trigger/server/trigger_db_helper.cpp new file mode 100755 index 0000000..8f4c928 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_db_helper.cpp @@ -0,0 +1,205 @@ +/* + * 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. + */ + +#include "trigger_db_helper.h" + +#include + +#include "intell_voice_log.h" +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" + +#define LOG_TAG "TriggerDbhelper" + +using namespace OHOS::NativeRdb; + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerModelOpenCallback : public RdbOpenCallback { +public: + int OnCreate(RdbStore &rdbStore) override; + int OnUpgrade(RdbStore &rdbStore, int oldVersion, int newVersion) override; +}; + +int TriggerModelOpenCallback::OnCreate(RdbStore &store) +{ + INTELL_VOICE_LOG_DEBUG("OnCreate"); + std::string CREATE_TABLE_Trigger = + std::string("CREATE TABLE IF NOT EXISTS trigger ") + + std::string("(model_uuid INTEGER PRIMARY KEY, vendor_uuid INTEGER, data BLOB, model_version INTEGER)"); + + return store.ExecuteSql(CREATE_TABLE_Trigger); +} + +int TriggerModelOpenCallback::OnUpgrade(RdbStore &store, int oldVersion, int newVersion) +{ + return E_OK; +} + +TriggerDbHelper::TriggerDbHelper() +{ + int errCode = E_OK; + RdbStoreConfig config("/data/service/el1/public/database/intell_voice_service_manager/triggerModel.db"); + TriggerModelOpenCallback helper; + store_ = RdbHelper::GetRdbStore(config, 1, helper, errCode); + if (store_ == nullptr) { + INTELL_VOICE_LOG_ERROR("store is nullptr"); + } +} + +TriggerDbHelper::~TriggerDbHelper() +{ + store_ = nullptr; +} + +bool TriggerDbHelper::UpdateGenericTriggerModel(std::shared_ptr model) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("db Update"); + + if (store_ == nullptr) { + INTELL_VOICE_LOG_ERROR("store is nullptr"); + return false; + } + + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("model is nullptr"); + return false; + } + + int64_t rowId = -1; + ValuesBucket values; + values.PutInt("model_uuid", model->GetUuid()); + values.PutInt("vendor_uuid", model->GetVendorUuid()); + values.PutBlob("data", model->GetData()); + values.PutInt("model_version", model->GetVersion()); + int ret = store_->InsertWithConflictResolution(rowId, "trigger", values, ConflictResolution::ON_CONFLICT_REPLACE); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("update generic model failed"); + return false; + } + return true; +} + +bool TriggerDbHelper::GetVendorUuid(std::unique_ptr &set, int32_t &vendorUuid) +{ + int columnIndex; + int ret = set->GetColumnIndex("vendor_uuid", columnIndex); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get model uuid column index"); + return false; + } + + ret = set->GetInt(columnIndex, vendorUuid); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get model uuid"); + return false; + } + return true; +} + +bool TriggerDbHelper::GetBlob(std::unique_ptr &set, std::vector &data) +{ + int columnIndex; + int ret = set->GetColumnIndex("data", columnIndex); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get data column index"); + return false; + } + + ret = set->GetBlob(columnIndex, data); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get data"); + return false; + } + return true; +} + +bool TriggerDbHelper::GetModelVersion(std::unique_ptr &set, int32_t &version) +{ + int columnIndex; + int ret = set->GetColumnIndex("model_version", columnIndex); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get model uuid column index"); + return false; + } + + ret = set->GetInt(columnIndex, version); + if (ret != E_OK) { + INTELL_VOICE_LOG_ERROR("failed to get model uuid"); + return false; + } + return true; +} + +std::shared_ptr TriggerDbHelper::GetGenericTriggerModel(const int32_t modelUuid) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("db get generic model"); + if (store_ == nullptr) { + INTELL_VOICE_LOG_ERROR("store is nullptr"); + return nullptr; + } + + std::unique_ptr set = store_->QuerySql( + "SELECT * FROM trigger WHERE model_uuid = ?", std::vector {std::to_string(modelUuid)}); + if (set == nullptr) { + INTELL_VOICE_LOG_ERROR("set is nullptr"); + return nullptr; + } + + set->GoToFirstRow(); + + int32_t vendorUuid; + if (!GetVendorUuid(set, vendorUuid)) { + INTELL_VOICE_LOG_ERROR("failed to get vendor uuid"); + return nullptr; + } + + std::vector data; + if (!GetBlob(set, data)) { + INTELL_VOICE_LOG_ERROR("failed to get data"); + return nullptr; + } + + int32_t modelVersion; + if (!GetModelVersion(set, modelVersion)) { + INTELL_VOICE_LOG_ERROR("failed to get model version"); + return nullptr; + } + + std::shared_ptr model = std::make_shared(modelUuid, modelVersion); + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to alloc model"); + return nullptr; + } + model->SetData(data); + return model; +} + +void TriggerDbHelper::DeleteGenericTriggerModel(const int32_t modelUuid) +{ + std::lock_guard lock(mutex_); + INTELL_VOICE_LOG_INFO("db Delete"); + if (store_ == nullptr) { + INTELL_VOICE_LOG_ERROR("store is nullptr"); + return; + } + int deletedRows; + store_->Delete(deletedRows, "trigger", "model_uuid = ?", std::vector {std::to_string(modelUuid)}); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS diff --git a/services/intell_voice_trigger/server/trigger_db_helper.h b/services/intell_voice_trigger/server/trigger_db_helper.h new file mode 100755 index 0000000..0f650fd --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_db_helper.h @@ -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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_DB_HELPER_H +#define INTELL_VOICE_TRIGGER_DB_HELPER_H +#include +#include + +#include "rdb_errno.h" +#include "rdb_helper.h" +#include "rdb_open_callback.h" +#include "trigger_base_type.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerDbHelper { +public: + TriggerDbHelper(); + ~TriggerDbHelper(); + bool UpdateGenericTriggerModel(std::shared_ptr model); + std::shared_ptr GetGenericTriggerModel(const int32_t modelUuid); + void DeleteGenericTriggerModel(const int32_t modelUuid); + +private: + bool GetVendorUuid(std::unique_ptr &set, int32_t &vendorUuid); + bool GetBlob(std::unique_ptr &set, std::vector &data); + bool GetModelVersion(std::unique_ptr &set, int32_t &version); + +private: + std::mutex mutex_; + std::shared_ptr store_ = nullptr; +}; +} +} +#endif diff --git a/services/intell_voice_trigger/server/trigger_detector.cpp b/services/intell_voice_trigger/server/trigger_detector.cpp new file mode 100755 index 0000000..4eac97d --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector.cpp @@ -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. + */ +#include "trigger_detector.h" +#include "intell_voice_log.h" +#include "trigger_detector_recognition_callback.h" +#include "memory_guard.h" + +#define LOG_TAG "TriggerDetector" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerDetector::TriggerDetector(int32_t uuid, std::shared_ptr service, + std::shared_ptr callback) : uuid_(uuid), service_(service) +{ + callback_ = std::make_shared(callback); + if (callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("callback_ is nullptr"); + } +} + +TriggerDetector::~TriggerDetector() +{ + service_ = nullptr; +} + +bool TriggerDetector::StartRecognition() +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + return false; + } + service_->StartRecognition(uuid_, callback_); + return true; +} + +bool TriggerDetector::StopRecognition() +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + return false; + } + service_->StopRecognition(uuid_, callback_); + return true; +} +} +} \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_detector.h b/services/intell_voice_trigger/server/trigger_detector.h new file mode 100755 index 0000000..91c560e --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_DETECTOR_H +#define INTELL_VOICE_TRIGGER_DETECTOR_H + +#include +#include "trigger_service.h" +#include "i_intell_voice_trigger_detector_callback.h" +#include "i_intell_voice_trigger_recognition_callback.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerDetector { +public: + TriggerDetector(int32_t uuid, std::shared_ptr service, + std::shared_ptr callback); + ~TriggerDetector(); + bool StartRecognition(); + bool StopRecognition(); + +private: + + int32_t uuid_ = -1; + std::shared_ptr service_ = nullptr; + std::shared_ptr callback_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_detector_callback.cpp b/services/intell_voice_trigger/server/trigger_detector_callback.cpp new file mode 100755 index 0000000..d6c7006 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector_callback.cpp @@ -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 + * + * 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. + */ +#include "trigger_detector_callback.h" +#include "intell_voice_log.h" +#include "wakeup_engine.h" + +using namespace OHOS::IntellVoiceEngine; +#define LOG_TAG "TriggerDetectorCallback" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerDetectorCallback::TriggerDetectorCallback(OnDetectedCb cb) : cb_(cb) +{} + +void TriggerDetectorCallback::OnDetected(const std::shared_ptr &event) +{ + if (event == nullptr) { + INTELL_VOICE_LOG_ERROR("event is nullptr"); + return; + } + + if (event->data_.size() > 0) { + INTELL_VOICE_LOG_INFO( + "receive DetectorEvent dataSize_: %{public}zu, data_[0]: %{public}d", event->data_.size(), event->data_[0]); + } + cb_(); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_detector_callback.h b/services/intell_voice_trigger/server/trigger_detector_callback.h new file mode 100755 index 0000000..e7ce6d6 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector_callback.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_DETECTOR_CALLBACK_H +#define INTELL_VOICE_TRIGGER_DETECTOR_CALLBACK_H + +#include +#include "i_intell_voice_trigger_detector_callback.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +using OnDetectedCb = std::function; + +class TriggerDetectorCallback : public IIntellVoiceTriggerDetectorCallback { +public: + explicit TriggerDetectorCallback(OnDetectedCb cb); + void OnDetected(const std::shared_ptr &event) override; + +private: + OnDetectedCb cb_; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_detector_recognition_callback.cpp b/services/intell_voice_trigger/server/trigger_detector_recognition_callback.cpp new file mode 100755 index 0000000..c5b948e --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector_recognition_callback.cpp @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#include "trigger_detector_recognition_callback.h" +#include "intell_voice_log.h" + +#define LOG_TAG "TriggerDetectorRecogCallback" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerDetectorRecognitionCallback::TriggerDetectorRecognitionCallback( + std::shared_ptr callback) : callback_(callback) +{ +} + +void TriggerDetectorRecognitionCallback::OnGenericTriggerDetected( + const std::shared_ptr event) +{ + if (event == nullptr || callback_ == nullptr) { + INTELL_VOICE_LOG_ERROR("event or callback_ is nullptr"); + return; + } + + std::shared_ptr eventPayLoad = std::make_shared( + event->audioFormat_, event->data_); + + if (eventPayLoad == nullptr) { + INTELL_VOICE_LOG_ERROR("event or callback_ is nullptr"); + return; + } + + callback_->OnDetected(eventPayLoad); +} +} +} \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_detector_recognition_callback.h b/services/intell_voice_trigger/server/trigger_detector_recognition_callback.h new file mode 100755 index 0000000..4ef6767 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_detector_recognition_callback.h @@ -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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_DETECTOR_RECOGNITION_CALLBACK_H +#define INTELL_VOICE_TRIGGER_DETECTOR_RECOGNITION_CALLBACK_H + +#include +#include +#include "i_intell_voice_trigger_recognition_callback.h" +#include "i_intell_voice_trigger_detector_callback.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerDetectorRecognitionCallback : public IIntellVoiceTriggerRecognitionCallback { +public: + explicit TriggerDetectorRecognitionCallback(std::shared_ptr callback); + ~TriggerDetectorRecognitionCallback() override {}; + void OnGenericTriggerDetected(const std::shared_ptr event) override; + +private: + + std::shared_ptr callback_ = nullptr; +}; +} +} +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_helper.cpp b/services/intell_voice_trigger/server/trigger_helper.cpp new file mode 100755 index 0000000..fa7b070 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_helper.cpp @@ -0,0 +1,314 @@ +/* + * 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. + */ +#include "trigger_helper.h" +#include "intell_voice_log.h" + +#include "trigger_connector_mgr.h" + +using namespace OHOS::HDI::IntelligentVoice::Trigger::V1_0; +using namespace std; +#define LOG_TAG "TriggerHelper" + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerModelData::TriggerModelData(int32_t uuid) +{ + uuid_ = uuid; +} + +TriggerModelData::~TriggerModelData() +{ +} + +void TriggerModelData::SetCallback(std::shared_ptr callback) +{ + if (callback == nullptr) { + INTELL_VOICE_LOG_ERROR("callback is nullptr"); + return; + } + callback_ = callback; +} + +std::shared_ptr TriggerModelData::GetCallback() +{ + return callback_; +} + +void TriggerModelData::SetModel(std::shared_ptr model) +{ + if (SameModel(model)) { + INTELL_VOICE_LOG_INFO("same model not need to update"); + return; + } + model_ = model; + model_->Print(); +} + +shared_ptr TriggerModelData::GetModel() +{ + return model_; +} + +bool TriggerModelData::SameModel(std::shared_ptr model) +{ + if (model == nullptr || model_ == nullptr) { + return false; + } + return model_->GetData() == model->GetData(); +} + +void TriggerModelData::SetState(ModelState state) +{ + state_ = state; +} + +ModelState TriggerModelData::GetState() +{ + return state_; +} + +void TriggerModelData::SetModelHandle(int32_t handle) +{ + modelHandle_ = handle; +} + +int32_t TriggerModelData::GetModelHandle() +{ + return modelHandle_; +} + +void TriggerModelData::Clear() +{ + callback_ = nullptr; +} + +TriggerHelper::TriggerHelper() +{ + moduleDesc_ = TriggerConnectorMgr::GetInstance()->ListConnectorModuleDescriptors(); +} + +TriggerHelper::~TriggerHelper() +{ + modelDataMap_.clear(); +} + +std::shared_ptr TriggerHelper::Create() +{ + return std::shared_ptr(new (std::nothrow) TriggerHelper()); +} + +int32_t TriggerHelper::StartGenericRecognition(int32_t uuid, std::shared_ptr model, + shared_ptr callback) +{ + INTELL_VOICE_LOG_INFO("enter"); + lock_guard lock(mutex_); + + auto modelData = GetTriggerModelData(uuid); + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get trigger model data"); + return -1; + } + + GetModule(); + + bool unload = !modelData->SameModel(model); + int32_t ret = InitRecognition(modelData, unload); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("failed to initialize recognition"); + return -1; + } + + modelData->SetModel(model); + modelData->SetCallback(callback); + + LoadModel(modelData); + return StartRecognition(modelData); +} + +int32_t TriggerHelper::StopGenericRecognition( + int32_t uuid, shared_ptr callback) +{ + INTELL_VOICE_LOG_INFO("enter"); + lock_guard lock(mutex_); + auto modelData = GetTriggerModelData(uuid); + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get trigger model data"); + return -1; + } + modelData->SetCallback(callback); + return StopRecognition(modelData); +} + +void TriggerHelper::GetModule() +{ + if (module_ != nullptr) { + return; + } + if (moduleDesc_.size() == 0) { + INTELL_VOICE_LOG_INFO("moduleDesc_ is empty"); + return; + } + module_ = + TriggerConnectorMgr::GetInstance()->GetConnectorModule(moduleDesc_[0].adapterName, shared_from_this()); + if (module_ == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get connector module"); + } +} + +int32_t TriggerHelper::InitRecognition(std::shared_ptr modelData, bool unload) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (modelData->GetState() == MODEL_NOTLOADED) { + return 0; + } + int32_t ret = StopRecognition(modelData); + if (unload) { + ret = UnloadModel(modelData); + } + modelData->Clear(); + return ret; +} + +int32_t TriggerHelper::StartRecognition(shared_ptr modelData) +{ + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("modelData is nullptr"); + return -1; + } + if (modelData->GetState() != MODEL_LOADED) { + return 0; + } + INTELL_VOICE_LOG_INFO("enter"); + if (module_ == nullptr) { + INTELL_VOICE_LOG_ERROR("module_ is nullptr"); + return -1; + } + auto ret = module_->Start(modelData->GetModelHandle()); + modelData->SetState(MODEL_STARTED); + return ret; +} + +int32_t TriggerHelper::StopRecognition(shared_ptr modelData) +{ + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("modelData is nullptr"); + return -1; + } + if (modelData->GetState() != MODEL_STARTED) { + return 0; + } + INTELL_VOICE_LOG_INFO("enter"); + if (module_ == nullptr) { + INTELL_VOICE_LOG_ERROR("module_ is nullptr"); + return -1; + } + auto ret = module_->Stop(modelData->GetModelHandle()); + modelData->SetState(MODEL_LOADED); + return ret; +} + +int32_t TriggerHelper::LoadModel(shared_ptr modelData) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("modelData is nullptr"); + return -1; + } + if (modelData->GetState() != MODEL_NOTLOADED) { + INTELL_VOICE_LOG_WARN("model is already loaded"); + return 0; + } + + if (module_ == nullptr) { + INTELL_VOICE_LOG_ERROR("module_ is nullptr"); + return -1; + } + + int32_t handle; + auto ret = module_->LoadModel(modelData->GetModel(), handle); + modelData->SetModelHandle(handle); + modelData->SetState(MODEL_LOADED); + INTELL_VOICE_LOG_INFO("exit, handle: %d", handle); + return ret; +} + +int32_t TriggerHelper::UnloadModel(shared_ptr modelData) +{ + if (modelData == nullptr) { + INTELL_VOICE_LOG_ERROR("modelData is nullptr"); + return -1; + } + if (modelData->GetState() != MODEL_LOADED) { + return 0; + } + INTELL_VOICE_LOG_INFO("enter"); + if (module_ == nullptr) { + INTELL_VOICE_LOG_ERROR("module_ is nullptr"); + return -1; + } + auto ret = module_->UnloadModel(modelData->GetModelHandle()); + modelData->SetState(MODEL_NOTLOADED); + return ret; +} + +shared_ptr TriggerHelper::GetTriggerModelData(int32_t uuid) +{ + INTELL_VOICE_LOG_INFO("enter, uuid is :%d", uuid); + auto it = modelDataMap_.find(uuid); + if (it != modelDataMap_.end() && it->second != nullptr) { + return it->second; + } + + auto modelData = std::make_shared(uuid); + if (modelData == nullptr) { + INTELL_VOICE_LOG_INFO("modelData is nullptr"); + return nullptr; + } + modelDataMap_.insert(std::make_pair(uuid, modelData)); + return modelData; +} + +void TriggerHelper::OnRecognition(int32_t modelHandle, const IntellVoiceRecognitionEvent &event) +{ + INTELL_VOICE_LOG_INFO("enter, modelHandle:%{public}d", modelHandle); + lock_guard lock(mutex_); + std::shared_ptr callback = nullptr; + for (auto iter : modelDataMap_) { + if (iter.second == nullptr) { + INTELL_VOICE_LOG_ERROR("uuid: %d, model data is nullptr", iter.first); + continue; + } + + if (iter.second->GetModelHandle() == modelHandle) { + callback = iter.second->GetCallback(); + break; + } + } + + if (callback == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger recognition callback is nullptr, modelHandle: %{public}d", modelHandle); + return; + } + + auto genericEvent = std::make_shared(); + if (genericEvent == nullptr) { + INTELL_VOICE_LOG_ERROR("genericEvent is nullptr"); + return; + } + genericEvent->modelHandle_ = modelHandle; + callback->OnGenericTriggerDetected(genericEvent); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_helper.h b/services/intell_voice_trigger/server/trigger_helper.h new file mode 100755 index 0000000..6c90d4c --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_helper.h @@ -0,0 +1,91 @@ +/* + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_HELPER_H +#define INTELL_VOICE_TRIGGER_HELPER_H + +#include +#include +#include "msg_handle_thread.h" +#include "trigger_base_type.h" +#include "i_intell_voice_trigger_recognition_callback.h" + +#include "i_intell_voice_trigger_connector_module.h" +#include "i_intell_voice_trigger_connector_callback.h" +#include "trigger_connector_common_type.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +enum ModelState { MODEL_NOTLOADED, MODEL_LOADED, MODEL_STARTED, MODEL_STATE_BUT }; + +class TriggerModelData { +public: + explicit TriggerModelData(int32_t uuid); + ~TriggerModelData(); + void SetCallback(std::shared_ptr callback); + std::shared_ptr GetCallback(); + void SetModel(std::shared_ptr model); + std::shared_ptr GetModel(); + void SetState(ModelState state); + ModelState GetState(); + void SetModelHandle(int32_t handle); + int32_t GetModelHandle(); + + bool SameModel(std::shared_ptr model); + void Clear(); + +public: + int32_t uuid_ = -1; + +private: + ModelState state_ = MODEL_NOTLOADED; + std::shared_ptr model_ = nullptr; + std::shared_ptr callback_ = nullptr; + int32_t modelHandle_ = 0; +}; + +class TriggerHelper : public IIntellVoiceTriggerConnectorCallback, + public std::enable_shared_from_this { +public: + ~TriggerHelper(); + + static std::shared_ptr Create(); + + int32_t StartGenericRecognition(int32_t uuid, std::shared_ptr model, + std::shared_ptr callback); + int32_t StopGenericRecognition(int32_t uuid, std::shared_ptr callback); + + std::shared_ptr GetTriggerModelData(int32_t uuid); + +private: + TriggerHelper(); + void GetModule(); + int32_t InitRecognition(std::shared_ptr modelData, bool unload); + int32_t StartRecognition(std::shared_ptr modelData); + int32_t StopRecognition(std::shared_ptr modelData); + int32_t LoadModel(std::shared_ptr modelData); + int32_t UnloadModel(std::shared_ptr modelData); + + void OnRecognition(int32_t modelHandle, const IntellVoiceRecognitionEvent &event) override; + +private: + std::mutex mutex_; + + std::map> modelDataMap_; + std::shared_ptr module_ = nullptr; + std::vector moduleDesc_; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_manager.cpp b/services/intell_voice_trigger/server/trigger_manager.cpp new file mode 100755 index 0000000..b390d47 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_manager.cpp @@ -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 + * + * 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. + */ +#include "trigger_manager.h" +#include "trigger_service.h" +#include "intell_voice_log.h" +#include "memory_guard.h" + +#define LOG_TAG "TriggerManager" + +namespace OHOS { +namespace IntellVoiceTrigger { +std::mutex TriggerManager::instanceMutex_; +std::shared_ptr TriggerManager::instance_ = nullptr; + +TriggerManager::TriggerManager() +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + service_ = std::make_shared(); + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + } +} + +TriggerManager::~TriggerManager() +{ + service_ = nullptr; +} + +std::shared_ptr TriggerManager::GetInstance() +{ + if (instance_ == nullptr) { + std::lock_guard autoLock(instanceMutex_); + if (instance_ == nullptr) { + instance_ = std::shared_ptr(new TriggerManager()); + } + } + return instance_; +} + +void TriggerManager::UpdateModel(std::shared_ptr model) +{ + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + } + service_->UpdateGenericTriggerModel(model); +} + +void TriggerManager::DeleteModel(int32_t uuid) +{ + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + } + service_->DeleteGenericTriggerModel(uuid); +} + +std::shared_ptr TriggerManager::GetModel(int32_t uuid) +{ + if (service_ == nullptr) { + INTELL_VOICE_LOG_ERROR("service_ is nullptr"); + return nullptr; + } + return service_->GetGenericTriggerModel(uuid); +} + +std::shared_ptr TriggerManager::CreateTriggerDetector( + int32_t uuid, std::shared_ptr callback) +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + std::shared_ptr detector = std::make_shared(uuid, service_, callback); + if (detector == nullptr) { + INTELL_VOICE_LOG_ERROR("detector is nullptr"); + return nullptr; + } + + detectors_[uuid] = detector; + return detector; +} + +void TriggerManager::ReleaseTriggerDetector(int32_t uuid) +{ + OHOS::IntellVoiceUtils::MemoryGuard memoryGuard; + auto it = detectors_.find(uuid); + if (it == detectors_.end()) { + return; + } + + detectors_.erase(it); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_manager.h b/services/intell_voice_trigger/server/trigger_manager.h new file mode 100755 index 0000000..e0b4ed5 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_manager.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_MANAGER_H +#define INTELL_VOICE_TRIGGER_MANAGER_H + +#include +#include +#include "trigger_base_type.h" +#include "trigger_service.h" +#include "trigger_detector.h" +#include "i_intell_voice_trigger_detector_callback.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerManager { +public: + ~TriggerManager(); + static std::shared_ptr GetInstance(); + + void UpdateModel(std::shared_ptr model); + void DeleteModel(int32_t uuid); + std::shared_ptr GetModel(int32_t uuid); + std::shared_ptr CreateTriggerDetector( + int32_t uuid, std::shared_ptr callback); + void ReleaseTriggerDetector(int32_t uuid); + +private: + explicit TriggerManager(); + +private: + std::map> detectors_; + std::shared_ptr service_; + + static std::mutex instanceMutex_; + static std::shared_ptr instance_; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_service.cpp b/services/intell_voice_trigger/server/trigger_service.cpp new file mode 100755 index 0000000..41f920a --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_service.cpp @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#include "trigger_service.h" + +#include + +#include "intell_voice_log.h" + +#define LOG_TAG "TriggerService" +using namespace std; + +namespace OHOS { +namespace IntellVoiceTrigger { +TriggerService::TriggerService() +{ + dbHelper_ = std::make_shared(); + if (dbHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("dbHelper_ is nullptr"); + } + + triggerHelper_ = TriggerHelper::Create(); + if (triggerHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("triggerHelper_ is nullptr"); + } +} + +TriggerService::~TriggerService() +{} + +void TriggerService::UpdateGenericTriggerModel(std::shared_ptr model) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (dbHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("dbHelper_ is nullptr"); + return; + } + + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger model is null"); + return; + } + + if (!dbHelper_->UpdateGenericTriggerModel(model)) { + INTELL_VOICE_LOG_ERROR("failed to update generic model"); + } +} + +void TriggerService::DeleteGenericTriggerModel(int32_t uuid) +{ + INTELL_VOICE_LOG_INFO("enter"); + if (dbHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("dbHelper_ is nullptr"); + return; + } + dbHelper_->DeleteGenericTriggerModel(uuid); +} + +std::shared_ptr TriggerService::GetGenericTriggerModel(int32_t uuid) +{ + INTELL_VOICE_LOG_INFO("enter"); + + if (dbHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("dbHelper_ is nullptr"); + return nullptr; + } + + auto model = dbHelper_->GetGenericTriggerModel(uuid); + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("failed to get generic trigger model"); + return nullptr; + } + + return model; +} + +int32_t TriggerService::StartRecognition( + int32_t uuid, std::shared_ptr callback) +{ + if (triggerHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger helper is nullptr"); + return -1; + } + + auto model = GetGenericTriggerModel(uuid); + if (model == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger model is nullptr, uuid:%{public}d", uuid); + return -1; + } + + return triggerHelper_->StartGenericRecognition(uuid, model, callback); +} + +int32_t TriggerService::StopRecognition(int32_t uuid, std::shared_ptr callback) +{ + if (triggerHelper_ == nullptr) { + INTELL_VOICE_LOG_ERROR("trigger helper is nullptr"); + return -1; + } + return triggerHelper_->StopGenericRecognition(uuid, callback); +} +} // namespace IntellVoiceTrigger +} // namespace OHOS \ No newline at end of file diff --git a/services/intell_voice_trigger/server/trigger_service.h b/services/intell_voice_trigger/server/trigger_service.h new file mode 100755 index 0000000..b214f82 --- /dev/null +++ b/services/intell_voice_trigger/server/trigger_service.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 + * + * 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. + */ +#ifndef INTELL_VOICE_TRIGGER_SERVICE_H +#define INTELL_VOICE_TRIGGER_SERVICE_H + +#include "trigger_db_helper.h" +#include "trigger_helper.h" + +namespace OHOS { +namespace IntellVoiceTrigger { +class TriggerService { +public: + TriggerService(); + ~TriggerService(); + void UpdateGenericTriggerModel(std::shared_ptr model); + void DeleteGenericTriggerModel(int32_t uuid); + std::shared_ptr GetGenericTriggerModel(int32_t uuid); + + int32_t StartRecognition(int32_t uuid, std::shared_ptr callback); + int32_t StopRecognition(int32_t uuid, std::shared_ptr callback); + +private: + std::shared_ptr dbHelper_ = nullptr; + std::shared_ptr triggerHelper_ = nullptr; +}; +} // namespace IntellVoiceTrigger +} // namespace OHOS +#endif \ No newline at end of file diff --git a/tests/BUILD.gn b/tests/BUILD.gn new file mode 100755 index 0000000..6a02871 --- /dev/null +++ b/tests/BUILD.gn @@ -0,0 +1,26 @@ +# 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("intell_voice_unit_test") { + testonly = true + deps = [ + "unittest/intell_voice_test:client_unit_test", + "unittest/intell_voice_test:trigger_manager_test", + "unittest/intell_voice_test:trigger_unit_test", + ] +} + +group("intell_voice_fuzz_test") { + testonly = true + deps = [ "fuzztest/Calculator_fuzzer:fuzztest" ] +} diff --git a/tests/fuzztest/Calculator_fuzzer/BUILD.gn b/tests/fuzztest/Calculator_fuzzer/BUILD.gn new file mode 100755 index 0000000..7367f0c --- /dev/null +++ b/tests/fuzztest/Calculator_fuzzer/BUILD.gn @@ -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 +# +# 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("//build/config/features.gni") +import("//build/test.gni") + +module_output_path = "ai_intell_voice_framework/audio_intell_voice" + +ohos_fuzztest("CalculatorFuzzTest") { + module_out_path = module_output_path + fuzz_config_file = "//foundation/ai/intelligent_voice_framework/tests/fuzztest/Calculator_fuzzer" + include_dirs = [] + cflags = [ + "-g", + "-O0", + "-Wno-unused-variable", + "-fno-omit-frame-pointer", + ] + sources = [ "Calculator_fuzzer.cpp" ] +} + +group("fuzztest") { + testonly = true + deps = [ ":CalculatorFuzzTest" ] +} diff --git a/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.cpp b/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.cpp new file mode 100755 index 0000000..0e3aae8 --- /dev/null +++ b/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.cpp @@ -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 + * + * 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. + */ + +#include +#include + +const int FUZZ_DATA_LEN = 3; +const int FUZZ_FST_DATA = 0; +const int FUZZ_SND_DATA = 1; +const int FUZZ_TRD_DATA = 2; +const int FUZZ_FTH_DATA = 3; + +namespace OHOS { + bool DoSomethingInterestingWithMyAPI(const uint8_t* data, size_t size) + { + if (data == nullptr) { + return false; + } + + bool result = false; + if (size >= FUZZ_DATA_LEN) { + result = data[FUZZ_FST_DATA] == 'F' && + data[FUZZ_SND_DATA] == 'U' && + data[FUZZ_TRD_DATA] == 'Z' && + data[FUZZ_FTH_DATA] == 'Z'; + } + return result; + } +} // namespace.OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ + /* Run your code on data */ + OHOS::DoSomethingInterestingWithMyAPI(data, size); + return 0; +} + diff --git a/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.h b/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.h new file mode 100755 index 0000000..73743ed --- /dev/null +++ b/tests/fuzztest/Calculator_fuzzer/Calculator_fuzzer.h @@ -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 + * + * 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. + */ + +#ifndef EXAMPLE_CALCULATOR_FUZZER_H_ +#define EXAMPLE_CALCULATOR_FUZZER_H_ + +#define FUZZ_PROJECT_NAME "calculator_fuzzer" + +#endif // EXAMPLE_CALCULATOR_FUZZER_H_ \ No newline at end of file diff --git a/tests/fuzztest/Calculator_fuzzer/corpus/init b/tests/fuzztest/Calculator_fuzzer/corpus/init new file mode 100755 index 0000000..d9719ca --- /dev/null +++ b/tests/fuzztest/Calculator_fuzzer/corpus/init @@ -0,0 +1,13 @@ +# 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. +FUZZ \ No newline at end of file diff --git a/tests/fuzztest/Calculator_fuzzer/project.xml b/tests/fuzztest/Calculator_fuzzer/project.xml new file mode 100755 index 0000000..4fdbc40 --- /dev/null +++ b/tests/fuzztest/Calculator_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 1000 + + 300 + + 4096 + + diff --git a/tests/unittest/intell_voice_test/BUILD.gn b/tests/unittest/intell_voice_test/BUILD.gn new file mode 100755 index 0000000..2bfd6d0 --- /dev/null +++ b/tests/unittest/intell_voice_test/BUILD.gn @@ -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 +# +# 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("//build/test.gni") + +module_output_path = "ai_intelligent_voice_framework/intell_voice" + +ohos_unittest("client_unit_test") { + testonly = true + module_out_path = module_output_path + sources = [ + "src/client_unit_test.cpp", + "src/engine_event_callback.cpp", + "src/wait_for_result.cpp", + ] + + include_dirs = [ + "include", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine/server/base", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_engine/proxy", + "//foundation/ai/intelligent_voice_framework/utils", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//foundation/ai/intelligent_voice_framework/services:intell_voice_proxy", + ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] +} + +ohos_unittest("trigger_unit_test") { + testonly = true + module_out_path = module_output_path + sources = [ "src/trigger_unit_test.cpp" ] + + include_dirs = [ + "//foundation/ai/intelligent_voice_framework/services/intell_voice_trigger/server", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_trigger/server/connector_mgr", + "//foundation/ai/intelligent_voice_framework/utils", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//foundation/ai/intelligent_voice_framework/services:intell_voice_server", + ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "relational_store:native_rdb", + ] +} + +ohos_unittest("trigger_manager_test") { + testonly = true + module_out_path = module_output_path + sources = [ "src/trigger_manager_test.cpp" ] + + include_dirs = [ + "//foundation/ai/intelligent_voice_framework/services/intell_voice_trigger/server", + "//foundation/ai/intelligent_voice_framework/services/intell_voice_trigger/server/connector_mgr", + "//foundation/ai/intelligent_voice_framework/utils", + ] + + cflags_cc = [ + "-Wno-error=unused-parameter", + "-DHILOG_ENABLE", + "-DENABLE_DEBUG", + ] + + deps = [ + "//foundation/ai/intelligent_voice_framework/services:intell_voice_server", + ] + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + "relational_store:native_rdb", + "safwk:system_ability_fwk", + "samgr:samgr_proxy", + ] +} diff --git a/tests/unittest/intell_voice_test/include/engine_event_callback.h b/tests/unittest/intell_voice_test/include/engine_event_callback.h new file mode 100755 index 0000000..6ce13b0 --- /dev/null +++ b/tests/unittest/intell_voice_test/include/engine_event_callback.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef ENGINE_EVENT_CALLBACK_H +#define ENGINE_EVENT_CALLBACK_H + +#include "i_intell_voice_engine_callback.h" +#include "i_intell_voice_engine.h" + +namespace OHOS { +namespace IntellVoiceTests { +class EngineEventCallback : public IntellVoiceEngine::IIntellVoiceEngineEventCallback { +public: + EngineEventCallback(sptr &engine, WaitForResult *wait) + { + engine_ = engine; + waitForResult_ = wait; + } + void OnEvent(const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent ¶m) override; + +private: + void ReadFile(const std::string path); + +private: + int32_t startCnt_ = 0; + uint32_t pcmSize_ = 0; + sptr engine_ = nullptr; + std::shared_ptr pcmData_ = nullptr; + WaitForResult *waitForResult_; +}; +} +} +#endif \ No newline at end of file diff --git a/tests/unittest/intell_voice_test/include/wait_for_result.h b/tests/unittest/intell_voice_test/include/wait_for_result.h new file mode 100755 index 0000000..05dbfa9 --- /dev/null +++ b/tests/unittest/intell_voice_test/include/wait_for_result.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 + * + * 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. + */ +#ifndef WAIT_FOR_RESULT_H +#define WAIT_FOR_RESULT_H + +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceTests { +class WaitForResult { +public: + void Wait(); + void SetIsReady(); + +private: + std::mutex mtx; + std::condition_variable condVar; + bool isReady = false; +}; +} +} +#endif \ No newline at end of file diff --git a/tests/unittest/intell_voice_test/src/client_unit_test.cpp b/tests/unittest/intell_voice_test/src/client_unit_test.cpp new file mode 100755 index 0000000..7671bed --- /dev/null +++ b/tests/unittest/intell_voice_test/src/client_unit_test.cpp @@ -0,0 +1,109 @@ +/* + * 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. + */ +#include +#include +#include +#include +#include +#include + +#include "iservice_registry.h" +#include "system_ability_definition.h" +#include "intell_voice_log.h" +#include "i_intell_voice_engine.h" +#include "i_intell_voice_service.h" +#include "intell_voice_service_proxy.h" +#include "intell_voice_engine_proxy.h" +#include "engine_callback_inner.h" +#include "engine_event_callback.h" +#include "wait_for_result.h" + +using namespace OHOS::IntellVoiceTests; +using namespace OHOS::IntellVoiceEngine; +using namespace OHOS; +using namespace testing::ext; + +static sptr g_sProxy = nullptr; +#define LOG_TAG "ClientTest" + +class ClientTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + std::shared_ptr cb_ = nullptr; +}; + +void ClientTest::SetUpTestCase(void) +{ + INTELL_VOICE_LOG_INFO("hello harmony OS!\n"); +} + +void ClientTest::TearDownTestCase(void) +{ +} + +void ClientTest::SetUp(void) +{ + auto samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ASSERT_NE(samgr, nullptr); + + sptr object = samgr->GetSystemAbility(INTELL_VOICE_SERVICE_ID); + ASSERT_NE(object, nullptr); + + g_sProxy = iface_cast(object); + ASSERT_NE(g_sProxy, nullptr); +} + +void ClientTest::TearDown(void) +{ +} + +HWTEST_F(ClientTest, ClientUtils, TestSize.Level1) +{ + WaitForResult waitForResult; + + sptr engine; + g_sProxy->CreateIntellVoiceEngine(INTELL_VOICE_ENROLL, engine); + ASSERT_NE(engine, nullptr); + + sptr callback = new(std::nothrow) EngineCallbackInner(); + ASSERT_NE(callback, nullptr); + cb_ = std::make_shared(engine, &waitForResult); + ASSERT_NE(cb_, nullptr); + + callback->SetEngineEventCallback(cb_); + sptr callbackObj = callback->AsObject(); + ASSERT_NE(callbackObj, nullptr); + + engine->SetCallback(callbackObj); + + IntellVoiceEngineInfo info = {}; + info.wakeupPhrase = "\xE5\xB0\x8F\xE8\x89\xBA\xE5\xB0\x8F\xE8\x89\xBA"; + info.isPcmFromExternal = true; + info.minBufSize = 1280; + info.sampleChannels = 1; + info.bitsPerSample = 16; + info.sampleRate = 16000; + + engine->Attach(info); + + waitForResult.Wait(); + + engine->Detach(); + + INTELL_VOICE_LOG_INFO("end\n"); +} diff --git a/tests/unittest/intell_voice_test/src/engine_event_callback.cpp b/tests/unittest/intell_voice_test/src/engine_event_callback.cpp new file mode 100755 index 0000000..31e6221 --- /dev/null +++ b/tests/unittest/intell_voice_test/src/engine_event_callback.cpp @@ -0,0 +1,100 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include "intell_voice_log.h" +#include "engine_event_callback.h" + +using namespace std; + +#define LOG_TAG "EngineEventCallback" + +namespace { +constexpr int32_t ENROLL_CNT = 3; +static constexpr uint32_t BUFFER_SIZE = 1280; +} + +namespace OHOS { +namespace IntellVoiceTests { +const std::string TEST_RESOURCE_PATH = "/data/test/resource/"; + +void EngineEventCallback::OnEvent( + const OHOS::HDI::IntelligentVoice::Engine::V1_0::IntellVoiceEngineCallBackEvent &event) +{ + INTELL_VOICE_LOG_INFO("OnEvent EngineCallBackInfo: msgId: %{public}d, errCode: %{public}d, context: %{public}s", + event.msgId, + event.result, + event.info.c_str()); + + if (event.msgId == HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_INIT_DONE) { + EXPECT_EQ(event.result, HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_OK); + startCnt_ = 1; + engine_->Start(false); + EngineEventCallback::ReadFile(TEST_RESOURCE_PATH + "one.pcm"); + } + + if (event.msgId == HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_ENROLL_COMPLETE) { + EXPECT_EQ(event.result, HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_OK); + if (startCnt_ < ENROLL_CNT) { + ++startCnt_; + engine_->Start(startCnt_ == ENROLL_CNT ? true : false); + if (startCnt_ == ENROLL_CNT) { + EngineEventCallback::ReadFile(TEST_RESOURCE_PATH + "three.pcm"); + } else { + EngineEventCallback::ReadFile(TEST_RESOURCE_PATH + "two.pcm"); + } + } else if (startCnt_ == ENROLL_CNT) { + engine_->SetParameter("CommitEnrollment=true"); + } + } + + if (event.msgId == HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_MSG_COMMIT_ENROLL_COMPLETE) { + EXPECT_EQ(event.result, HDI::IntelligentVoice::Engine::V1_0::INTELL_VOICE_ENGINE_OK); + waitForResult_->SetIsReady(); + } +} + +void EngineEventCallback::ReadFile(const std::string path) +{ + INTELL_VOICE_LOG_INFO("path: %{public}s", path.c_str()); + ifstream infile; + infile.open(path, ios::in | ios::binary); + + if (!infile.is_open()) { + INTELL_VOICE_LOG_INFO("open file failed"); + } + + infile.seekg(0, infile.end); + pcmSize_ = static_cast(infile.tellg()); + pcmData_ = std::shared_ptr(new uint8_t[pcmSize_], [](uint8_t *p) { delete[] p; }); + if (pcmData_ == nullptr) { + INTELL_VOICE_LOG_INFO("pcmData_ is null"); + return; + } + INTELL_VOICE_LOG_INFO("read pcm, pcmSize:%u", pcmSize_); + infile.seekg(0, infile.beg); + infile.read(reinterpret_cast(pcmData_.get()), pcmSize_); + infile.close(); + + for (uint32_t i = 0; i < pcmSize_ / BUFFER_SIZE; i++) { + engine_->WriteAudio(pcmData_.get() + i * BUFFER_SIZE, BUFFER_SIZE); + } + engine_->SetParameter("end_of_pcm=true"); +} +} // namespace IntellVoiceTests +} // namespace OHOS diff --git a/tests/unittest/intell_voice_test/src/trigger_manager_test.cpp b/tests/unittest/intell_voice_test/src/trigger_manager_test.cpp new file mode 100755 index 0000000..0401159 --- /dev/null +++ b/tests/unittest/intell_voice_test/src/trigger_manager_test.cpp @@ -0,0 +1,107 @@ +/* + * 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. + */ +#include +#include +#include +#include + +#include +#include "intell_voice_log.h" + +#include "trigger_manager.h" +#include "trigger_base_type.h" +#include "trigger_detector_callback.h" + +#define LOG_TAG "TriggerManagerTest" + +using namespace OHOS::IntellVoiceTrigger; +using namespace OHOS; +using namespace testing::ext; +using namespace std; + +static std::shared_ptr triggerManager = nullptr; + +class TriggerManagerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + void TriggerManagerTestCallBack(); + void ReadFile(const std::string path); + std::vector modelData; + bool testResult = false; +}; + +void TriggerManagerTest::SetUpTestCase(void) +{} + +void TriggerManagerTest::TearDownTestCase(void) +{} + +void TriggerManagerTest::SetUp(void) +{ + triggerManager = TriggerManager::GetInstance(); + ASSERT_NE(triggerManager, nullptr); + ReadFile("/data/test/resource/model_one.txt"); +} + +void TriggerManagerTest::TearDown(void) +{ + triggerManager = nullptr; +} + +void TriggerManagerTest::TriggerManagerTestCallBack(void) +{ + INTELL_VOICE_LOG_INFO("enter"); + testResult = true; +} + +void TriggerManagerTest::ReadFile(const std::string path) +{ + INTELL_VOICE_LOG_INFO("path: %{public}s", path.c_str()); + ifstream infile; + infile.open(path, ios::in); + + if (!infile.is_open()) { + INTELL_VOICE_LOG_INFO("open file failed"); + } + + infile.seekg(0, infile.end); + uint32_t modelSize = static_cast(infile.tellg()); + std::vector datas(modelSize); + infile.seekg(0, infile.beg); + infile.read(reinterpret_cast(datas.data()), modelSize); + infile.close(); + + modelData = datas; +} + +HWTEST_F(TriggerManagerTest, start_recognition_001, TestSize.Level1) +{ + int32_t uuid = 11; + auto model = std::make_shared(uuid, 100); + model->SetData(modelData); + triggerManager->UpdateModel(model); + + std::shared_ptr cb = std::make_shared( + std::bind(&TriggerManagerTest::TriggerManagerTestCallBack, this)); + auto detector = triggerManager->CreateTriggerDetector(uuid, cb); + sleep(1); + detector->StartRecognition(); + triggerManager->DeleteModel(uuid); + + EXPECT_EQ(true, testResult); +} diff --git a/tests/unittest/intell_voice_test/src/trigger_unit_test.cpp b/tests/unittest/intell_voice_test/src/trigger_unit_test.cpp new file mode 100755 index 0000000..f96c850 --- /dev/null +++ b/tests/unittest/intell_voice_test/src/trigger_unit_test.cpp @@ -0,0 +1,89 @@ +/* + * 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. + */ +#include +#include +#include + +#include "intell_voice_log.h" +#include "trigger_manager.h" +#include "trigger_base_type.h" +#include "trigger_detector_callback.h" + +#define LOG_TAG "TriggerTest" + +using namespace OHOS::IntellVoiceTrigger; +using namespace OHOS; +using namespace testing::ext; + +static std::shared_ptr triggerManager = nullptr; + +class TriggerTest : public testing::Test { +public: + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +void TriggerTest::SetUpTestCase(void) +{} + +void TriggerTest::TearDownTestCase(void) +{} + +void TriggerTest::SetUp(void) +{ + triggerManager = TriggerManager::GetInstance(); + ASSERT_NE(triggerManager, nullptr); +} + +void TriggerTest::TearDown(void) +{ + triggerManager = nullptr; +} + +HWTEST_F(TriggerTest, trigger_db_helper_001, TestSize.Level1) +{ + // insert model + int32_t uuid = 11; + auto model = std::make_shared(uuid, 100); + uint8_t data[4] = {0, 1, 2, 3}; + model->SetData(data, sizeof(data)); + + std::vector expect(sizeof(data)); + memcpy(&expect[0], data, sizeof(data)); + + triggerManager->UpdateModel(model); + auto result = triggerManager->GetModel(uuid); + EXPECT_EQ(expect, result->GetData()); + + // update model + uint8_t newdata[4] = {0, 1, 2, 5}; + model->SetData(newdata, sizeof(newdata)); + + expect.clear(); + expect.resize(sizeof(newdata)); + memcpy(&expect[0], newdata, sizeof(newdata)); + + triggerManager->UpdateModel(model); + result = triggerManager->GetModel(uuid); + EXPECT_EQ(expect, result->GetData()); + + // delete model + triggerManager->DeleteModel(uuid); + result = triggerManager->GetModel(uuid); + EXPECT_EQ(nullptr, result); +} + diff --git a/tests/unittest/intell_voice_test/src/wait_for_result.cpp b/tests/unittest/intell_voice_test/src/wait_for_result.cpp new file mode 100755 index 0000000..7883f3c --- /dev/null +++ b/tests/unittest/intell_voice_test/src/wait_for_result.cpp @@ -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 + * + * 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. + */ +#include "wait_for_result.h" +#include "intell_voice_log.h" + +#define LOG_TAG "WaitForResult" + +namespace OHOS { +namespace IntellVoiceTests { +void WaitForResult::Wait() +{ + std::unique_lock lock(mtx); + condVar.wait(lock, [this] {return isReady;}); +} + +void WaitForResult::SetIsReady() +{ + { + std::lock_guard lock(mtx); + isReady = true; + } + INTELL_VOICE_LOG_INFO("notify_one"); + condVar.notify_one(); +} +} +} diff --git a/utils/BUILD.gn b/utils/BUILD.gn new file mode 100755 index 0000000..9bc07e5 --- /dev/null +++ b/utils/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. + +import("//build/ohos.gni") + +ohos_shared_library("intell_voice_utils") { + configs = [ "//build/config/compiler:exceptions" ] + + include_dirs = [ "//foundation/ai/intelligent_voice_framework/utils" ] + + sources = [ + "base_thread.cpp", + "memory_guard.cpp", + "message_queue.cpp", + "msg_handle_thread.cpp", + "string_util.cpp", + "time_util.cpp", + ] + + defines = [] + if (use_musl) { + if (use_jemalloc && use_jemalloc_dfx_intf) { + defines += [ "CONFIG_USE_JEMALLOC_DFX_INTF" ] + } + } + + external_deps = [ + "c_utils:utils", + "hiviewdfx_hilog_native:libhilog", + ] + + cflags = [ + "-Wall", + "-Wextra", + "-Werror", + "-DHAVE_CONFIG_H", + "-fno-strict-aliasing", + "-Wno-sign-compare", + "-Wno-builtin-requires-header", + "-Wno-implicit-function-declaration", + "-Wno-format", + "-Wno-int-conversion", + "-Wno-unused-function", + "-Wno-unused-parameter", + "-Wno-thread-safety-attributes", + "-Wno-inconsistent-missing-override", + "-fno-rtti", + "-fno-exceptions", + "-ffunction-sections", + "-fdata-sections", + "-Wheader-hygiene", + ] + + ldflags = [ "-Wl" ] + + subsystem_name = "ai" + part_name = "intelligent_voice_framework" +} diff --git a/utils/base_constants.h b/utils/base_constants.h new file mode 100755 index 0000000..b96b9db --- /dev/null +++ b/utils/base_constants.h @@ -0,0 +1,32 @@ +/* + * 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. + */ +#ifndef BASE_CONSTANTS_H +#define BASE_CONSTANTS_H + +#include + +namespace OHOS { +namespace IntellVoiceUtils { +const int32_t H_PER_MIN = 60; +const int32_t MIN_PER_S = 60; +const int32_t S_PER_MS = 1000; +const int32_t MS_PER_US = 1000; +const int32_t US_PER_NS = 1000; + +const uint32_t MB_PER_KB = 1024; +const uint32_t KB_PER_B = 1024; +} +} +#endif diff --git a/utils/base_thread.cpp b/utils/base_thread.cpp new file mode 100755 index 0000000..84df145 --- /dev/null +++ b/utils/base_thread.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 + * + * 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. + */ +#include "base_thread.h" +#include +#include "intell_voice_log.h" + +#define LOG_TAG "BaseThread" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceUtils { +BaseThread::BaseThread() : tid(0), isRuning(false) +{ +} + +BaseThread::~BaseThread() +{ + if (isRuning) { + pthread_detach(tid); + } +} + +void *BaseThread::RunInThread(void *arg) +{ + BaseThread *pt = static_cast(arg); + pt->Run(); + + return nullptr; +} + +void BaseThread::Start() +{ + std::lock_guard lock(mutex_); + + int ret = pthread_create(&tid, nullptr, BaseThread::RunInThread, this); + if (ret != 0) { + INTELL_VOICE_LOG_ERROR("create thread failed"); + return; + } + + isRuning = true; +} + +void BaseThread::Join() +{ + std::lock_guard lock(mutex_); + + if (!isRuning) { + return; + } + + pthread_join(tid, nullptr); + isRuning = false; +} + +bool BaseThread::IsRuning() const +{ + return isRuning; +} + +pid_t BaseThread::Gettid() const +{ + return tid; +} +} +} diff --git a/utils/base_thread.h b/utils/base_thread.h new file mode 100755 index 0000000..2f8764c --- /dev/null +++ b/utils/base_thread.h @@ -0,0 +1,47 @@ +/* + * 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. + */ +#ifndef BASE_THREAD_H +#define BASE_THREAD_H + +#include +#include +#include +#include + +namespace OHOS { +namespace IntellVoiceUtils { +class BaseThread { +public: + BaseThread(); + virtual ~BaseThread(); + + void Start(); + void Join(); + bool IsRuning() const; + + pid_t Gettid() const; + +protected: + virtual void Run() = 0; + +private: + static void *RunInThread(void *arg); + pthread_t tid; + bool isRuning; + std::mutex mutex_ {}; +}; +} +} +#endif diff --git a/utils/intell_voice_generic_factory.h b/utils/intell_voice_generic_factory.h new file mode 100755 index 0000000..6e6829f --- /dev/null +++ b/utils/intell_voice_generic_factory.h @@ -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. + */ + +#ifndef INTELL_VOICE_GENERIC_FACTORY_H +#define INTELL_VOICE_GENERIC_FACTORY_H +#include + +namespace OHOS { +namespace IntellVoiceUtils { +template +class UniquePtrFactory { +public: + using UniqueProductPtr = std::unique_ptr; + + template + static UniqueProductPtr CreateInstance(Args && ...args) + { + T *instance = new(std::nothrow) T {}; + if (instance == nullptr) { + return UniqueProductPtr {nullptr, nullptr}; + } + if (!instance->Init(std::forward(args)...)) { + delete instance; + return UniqueProductPtr {nullptr, nullptr}; + } + return UniqueProductPtr(instance, DestroyInstance); + } + +private: + static void DestroyInstance(T *ptr) + { + delete ptr; + } +}; + +template +using UniqueProductType = typename UniquePtrFactory::UniqueProductPtr; + +template +class SptrFactory { +public: + using SptrProductPtr = OHOS::sptr; + + template + static SptrProductPtr CreateInstance(Args && ...args) + { + T *instance = new(std::nothrow) T {}; + if (instance == nullptr) { + return SptrProductPtr { nullptr }; + } + if (!instance->Init(std::forward(args)...)) { + delete instance; + return SptrProductPtr { nullptr }; + } + return SptrProductPtr(instance); + } +}; + +template +using SptrProductType = typename SptrFactory::ProductPtr; +} +} +#endif diff --git a/utils/intell_voice_log.h b/utils/intell_voice_log.h new file mode 100755 index 0000000..627c1c2 --- /dev/null +++ b/utils/intell_voice_log.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 + * + * 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. + */ +#ifndef INTELL_VOICE_LOG_H +#define INTELL_VOICE_LOG_H + +#include +#include "hilog/log.h" + +#undef LOG_DOMAIN +#define LOG_DOMAIN 0xD002500 +#undef LOG_TAG + +#define INTELL_VOICE_LOG_DEBUG(fmt, ...) \ + HILOG_DEBUG(LOG_CORE, "[%{public}s:%{public}d]: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define INTELL_VOICE_LOG_ERROR(fmt, ...) \ + HILOG_ERROR(LOG_CORE, "[%{public}s:%{public}d]: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define INTELL_VOICE_LOG_WARN(fmt, ...) \ + HILOG_WARN(LOG_CORE, "[%{public}s:%{public}d]: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define INTELL_VOICE_LOG_INFO(fmt, ...) \ + HILOG_INFO(LOG_CORE, "[%{public}s:%{public}d]: " fmt, __func__, __LINE__, ##__VA_ARGS__) +#define INTELL_VOICE_LOG_FATAL(fmt, ...) \ + HILOG_FATAL(LOG_CORE, "[%{public}s:%{public}d]: " fmt, __func__, __LINE__, ##__VA_ARGS__) + +#endif diff --git a/utils/memory_guard.cpp b/utils/memory_guard.cpp new file mode 100755 index 0000000..6e84b0b --- /dev/null +++ b/utils/memory_guard.cpp @@ -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 + * + * 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. + */ +#include "memory_guard.h" +#include +#include +#include "intell_voice_log.h" + +#define LOG_TAG "MemoryGaurd" + +namespace OHOS { +namespace IntellVoiceUtils { +MemoryGuard::MemoryGuard() +{ +#ifdef CONFIG_USE_JEMALLOC_DFX_INTF + // 0 indicates success + int32_t ret1 = mallopt(M_SET_THREAD_CACHE, M_THREAD_CACHE_DISABLE); + int32_t ret2 = mallopt(M_DELAYED_FREE, M_DELAYED_FREE_DISABLE); + INTELL_VOICE_LOG_INFO("disable tcache and delay free, result:%{public}d, %{public}d", ret1, ret2); +#endif +} + +MemoryGuard::~MemoryGuard() +{ +#ifdef CONFIG_USE_JEMALLOC_DFX_INTF + int32_t err = mallopt(M_FLUSH_THREAD_CACHE, 0); + INTELL_VOICE_LOG_INFO("flush cache, result: %{public}d", err); +#endif +} +} +} \ No newline at end of file diff --git a/utils/memory_guard.h b/utils/memory_guard.h new file mode 100755 index 0000000..fecf4d0 --- /dev/null +++ b/utils/memory_guard.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 + * + * 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. + */ +#ifndef MEMORY_GUARD +#define MEMORY_GUARD + +namespace OHOS { +namespace IntellVoiceUtils { +class MemoryGuard final { +public: + MemoryGuard(); + ~MemoryGuard(); +}; +} +} +#endif \ No newline at end of file diff --git a/utils/message_queue.cpp b/utils/message_queue.cpp new file mode 100755 index 0000000..020b1da --- /dev/null +++ b/utils/message_queue.cpp @@ -0,0 +1,162 @@ +/* + * 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. + */ +#include "message_queue.h" +#include "intell_voice_log.h" + +#define LOG_TAG "MesaageQueue" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceUtils { +Message::Message(uint32_t what) +{ + mWhat = what; + arg1 = 0; + arg2 = 0; +} + +Message::Message(uint32_t what, int32_t arg1) +{ + mWhat = what; + this->arg1 = arg1; +} + +Message::Message(uint32_t what, int32_t arg1, int32_t arg2, float arg3) +{ + mWhat = what; + this->arg1 = arg1; + this->arg2 = arg2; + this->arg3 = arg3; +} + +Message::Message(uint32_t what, int32_t arg1, int32_t arg2, string obj) +{ + mWhat = what; + this->arg1 = arg1; + this->arg2 = arg2; + this->obj = obj; +} + +Message::Message(uint32_t what, int32_t arg1, int32_t arg2, float arg3, string obj) +{ + mWhat = what; + this->arg1 = arg1; + this->arg2 = arg2; + this->arg3 = arg3; + this->obj = obj; +} + +Message::Message(uint32_t what, std::shared_ptr obj2) +{ + mWhat = what; + this->obj2 = obj2; +} + +Message::Message(uint32_t what, std::shared_ptr obj2, std::shared_ptr obj3) +{ + mWhat = what; + this->obj2 = obj2; + this->obj3 = obj3; +} + +Message::Message(uint32_t what, void* voidPtr) +{ + mWhat = what; + this->voidPtr = voidPtr; +} + +Message::Message(uint32_t what, void* voidPtr, int32_t arg1) +{ + mWhat = what; + this->voidPtr = voidPtr; + this->arg1 = arg1; +} + +Message::~Message() +{ + voidPtr = nullptr; +} + +MessageQueue::MessageQueue(uint32_t size) +{ + mSize = size; + mLock = PTHREAD_MUTEX_INITIALIZER; + pthread_condattr_t attr; + int result = pthread_condattr_init(&attr); + result += pthread_cond_init(&mCond, &attr); + result += pthread_condattr_destroy(&attr); + if (result != 0) { + INTELL_VOICE_LOG_ERROR("message queue construct init cond failed"); + } +} + +MessageQueue::~MessageQueue() +{ + int result = pthread_mutex_destroy(&mLock); + result += pthread_cond_destroy(&mCond); + if (result != 0) { + INTELL_VOICE_LOG_ERROR("message queue deconstruct destroy cond failed"); + } +} + +shared_ptr MessageQueue::ReceiveMsg() +{ + shared_ptr msg = nullptr; + pthread_mutex_lock(&mLock); + while (mQueue.empty()) { + pthread_cond_wait(&mCond, &mLock); + } + + msg = mQueue.front(); + mQueue.pop(); + pthread_mutex_unlock(&mLock); + + return msg; +} + +bool MessageQueue::SendMsg(shared_ptr msg) +{ + pthread_mutex_lock(&mLock); + if (static_cast(mQueue.size()) >= mSize || msg == nullptr) { + INTELL_VOICE_LOG_WARN("send message failed, msg queue full(qsize %{public}d)", static_cast(mQueue.size())); + pthread_mutex_unlock(&mLock); + return false; + } + + try { + mQueue.push(msg); + } catch (const std::length_error& err) { + INTELL_VOICE_LOG_ERROR("messagequeue push, length error"); + pthread_mutex_unlock(&mLock); + return false; + } + + pthread_cond_signal(&mCond); + pthread_mutex_unlock(&mLock); + + return true; +} + +void MessageQueue::Clear() +{ + pthread_mutex_lock(&mLock); + while (!mQueue.empty()) { + mQueue.pop(); + } + pthread_mutex_unlock(&mLock); +} +} +} diff --git a/utils/message_queue.h b/utils/message_queue.h new file mode 100755 index 0000000..5101b24 --- /dev/null +++ b/utils/message_queue.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 + * + * 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. + */ +#ifndef MESSAGE_QUEUE_H +#define MESSAGE_QUEUE_H + +#include +#include +#include +#include +#include +#include +#include "nocopyable.h" + +namespace OHOS { +namespace IntellVoiceUtils { +struct SynInfo { + std::mutex mMutex; + std::condition_variable mCV; +}; +struct Message { +public: + explicit Message(uint32_t what); + Message(uint32_t what, int32_t arg1); + Message(uint32_t what, int32_t arg1, int32_t arg2, float arg3); + Message(uint32_t what, int32_t arg1, int32_t arg2, std::string obj); + Message(uint32_t what, int32_t arg1, int32_t arg2, float arg3, std::string obj); + Message(uint32_t what, std::shared_ptr obj2); + Message(uint32_t what, std::shared_ptr obj2, std::shared_ptr obj3); + Message(uint32_t what, void* voidPtr); + Message(uint32_t what, void* voidPtr, int32_t arg1); + ~Message(); + + uint32_t mWhat { 0 }; + int32_t arg1 { 0 }; + int32_t arg2 { 0 }; + float arg3 { 0.0 }; + std::string obj; + std::shared_ptr obj2 { nullptr }; + std::shared_ptr obj3 { nullptr }; + void* voidPtr { nullptr }; + uint32_t mCallbackId { 0 }; + + std::shared_ptr result { nullptr }; +}; + +class MessageQueue { +public: + explicit MessageQueue(uint32_t size); + ~MessageQueue(); + std::shared_ptr ReceiveMsg(); + bool SendMsg(std::shared_ptr msg); + void Clear(); + +private: + DISALLOW_COPY(MessageQueue); + DISALLOW_MOVE(MessageQueue); + + uint32_t mSize; + pthread_mutex_t mLock; + pthread_cond_t mCond; + std::queue> mQueue; +}; +} +} +#endif diff --git a/utils/msg_handle_thread.cpp b/utils/msg_handle_thread.cpp new file mode 100755 index 0000000..3fb208e --- /dev/null +++ b/utils/msg_handle_thread.cpp @@ -0,0 +1,132 @@ +/* + * 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. + */ +#include "msg_handle_thread.h" +#include +#include +#include "intell_voice_log.h" + +#define LOG_TAG "MsgHandleThread" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceUtils { +static const uint32_t MSQ_QUEUE_MAX_LEN = 100; +static const int32_t MSG_MAX_SYNC_TIMEOUT = 5; + +MsgHandleThread::MsgHandleThread() : msgQue(MSQ_QUEUE_MAX_LEN), callbackThread(nullptr) {} + +MsgHandleThread::MsgHandleThread(std::shared_ptr callbackMsgQue) + : callbackMsgQue(callbackMsgQue), msgQue(MSQ_QUEUE_MAX_LEN), callbackThread(nullptr) +{} + +MsgHandleThread::MsgHandleThread(MsgHandleThread *callbackThread) + : msgQue(MSQ_QUEUE_MAX_LEN), callbackThread(callbackThread) +{} + +MsgHandleThread::~MsgHandleThread() {} + +void MsgHandleThread::SetCallbackThread(MsgHandleThread *tmpCallbackThread) +{ + callbackThread = tmpCallbackThread; +} + +// the default realization is for debug, subclass should override this func +bool MsgHandleThread::HandleMsg(Message &msg) +{ + INTELL_VOICE_LOG_INFO("run thread %u process msg %u", Gettid(), msg.mWhat); + + SendbackMsg(msg); + + return true; +} + +bool MsgHandleThread::SendMsg(Message msg) +{ + try { + msgQue.SendMsg(std::make_shared(msg)); + } catch (const std::length_error& err) { + INTELL_VOICE_LOG_ERROR("length error"); + return false; + } + + return true; +} + +bool MsgHandleThread::SendMsg(std::shared_ptr msg) +{ + if (msg == nullptr) { + return false; + } + + msgQue.SendMsg(msg); + return true; +} + +bool MsgHandleThread::SendSynMsg(shared_ptr msg) +{ + if (msg == nullptr) { + return false; + } + + msg->result = std::make_shared(); + if (msg->result == nullptr) { + INTELL_VOICE_LOG_ERROR("create sync info failed"); + return false; + } + + unique_lock lock(msg->result->mMutex); + msgQue.SendMsg(msg); + if (msg->result->mCV.wait_for(lock, chrono::seconds(MSG_MAX_SYNC_TIMEOUT)) == std::cv_status::no_timeout) { + return true; + } else { + INTELL_VOICE_LOG_WARN("send syn msg timeout"); + return false; + } +} + +void MsgHandleThread::SendbackMsg(Message msg) +{ + if (callbackThread != nullptr) { + callbackThread->SendMsg(msg); + } + + if (callbackMsgQue != nullptr) { + callbackMsgQue->SendMsg(make_shared(msg)); + } +} + +void MsgHandleThread::Run() +{ + bool isQuit = false; + + while (!isQuit) { + shared_ptr msg = msgQue.ReceiveMsg(); + + isQuit = HandleMsg(*msg); + + if (msg->result != nullptr) { + unique_lock lock(msg->result->mMutex); + msg->result->mCV.notify_all(); + } + } +} + +string MsgHandleThread::ToString() const +{ + return ""; +} +} +} diff --git a/utils/msg_handle_thread.h b/utils/msg_handle_thread.h new file mode 100755 index 0000000..b22cd8c --- /dev/null +++ b/utils/msg_handle_thread.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 + * + * 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. + */ +#ifndef MSG_HANDLE_THREAD_H +#define MSG_HANDLE_THREAD_H + +#include +#include "message_queue.h" +#include "base_thread.h" + +namespace OHOS { +namespace IntellVoiceUtils { +class MsgHandleThread : public BaseThread { +public: + MsgHandleThread(); + // for compatible with wakeup engine + explicit MsgHandleThread(std::shared_ptr callbackMsgQue); + explicit MsgHandleThread(MsgHandleThread *callbackThread); + ~MsgHandleThread() override; + bool SendMsg(Message msg); + bool SendMsg(std::shared_ptr msg); + bool SendSynMsg(std::shared_ptr msg); + void SetCallbackThread(MsgHandleThread *tmpCallbackThread); + // for debug + std::string ToString() const; + +protected: + // subclass should override this function most time + virtual bool HandleMsg(Message &msg); + virtual void SendbackMsg(Message msg); + +private: + void Run() override; + + std::shared_ptr callbackMsgQue { nullptr }; + MessageQueue msgQue; + MsgHandleThread *callbackThread; +}; +} +} +#endif diff --git a/utils/scope_guard.h b/utils/scope_guard.h new file mode 100755 index 0000000..9e364a7 --- /dev/null +++ b/utils/scope_guard.h @@ -0,0 +1,97 @@ +/* + * 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. + */ +#ifndef SCOPE_GUARD_H +#define SCOPE_GUARD_H + +#include + +namespace OHOS { +namespace IntellVoiceUtils { +template +class ScopeGuard { +public: + ScopeGuard(Func &&f) : mFunc(std::forward(f)), mActive(true) + { + } + + ScopeGuard(ScopeGuard &&rhs) : mFunc(std::move(rhs.mFunc)), mActive(rhs.mActive) + { + rhs.Disable(); + } + + ~ScopeGuard() + { + if (mActive) { + mFunc(); + } + } + + void Disable() + { + mActive = false; + } + + bool Active() const + { + return mActive; + } + + void EarlyExit() + { + if (mActive) { + mFunc(); + } + mActive = false; + } +private: + Func mFunc; + bool mActive; + ScopeGuard() = delete; + ScopeGuard(const ScopeGuard &) = delete; + ScopeGuard &operator=(const ScopeGuard &) = delete; + ScopeGuard &operator=(ScopeGuard &&) = delete; +}; + +// tag dispatch +struct ScopeGuardOnExit {}; + +template +inline ScopeGuard operator+(ScopeGuardOnExit, Func &&fn) +{ + return ScopeGuard(std::forward(fn)); +} +} +} + +/*** ScopeGuard ensure the specified function which is created by ON_SCOPE_EXIT is executed no matter how the current +**** scope exit. +**** when use ON_SCOPE_EXIT macro, the format is: +**** ON_SCOPE_EXIT { +********your code +**** }; +*/ +#define ON_SCOPE_EXIT \ + auto __onScopeGuardExit__ = OHOS::IntellVoiceUtils::ScopeGuardOnExit() + [&]() + +#define CANCEL_SCOPE_EXIT \ + (__onScopeGuardExit__.Disable()) + +#define EARLY_SCOPE_EXIT \ + (__onScopeGuardExit__.EarlyExit()) + +#define ON_SCOPE_EXIT_WITH_NAME(variable_name) \ + auto variable_name = OHOS::IntellVoiceUtils::ScopeGuardOnExit() + [&]() + +#endif diff --git a/utils/string_util.cpp b/utils/string_util.cpp new file mode 100755 index 0000000..ec0c8ea --- /dev/null +++ b/utils/string_util.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 + * + * 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. + */ + +#include "string_util.h" +#include +#include +#include +#include +#include "intell_voice_log.h" + +#undef LOG_TAG +#define LOG_TAG "StringUtil" + +using namespace std; + +namespace OHOS { +namespace IntellVoiceUtils { +static const char16_t DELIMITER_EQUAL_SIGN = '='; + +// #ABC#WWW##XYZ#---->vector[0]: ABC, vector[1]: WWW, vector[2]: XYZ +void StringUtil::Split(const string &str, const string &sep, vector &res) +{ + res.clear(); + string tmpStr = str; + unsigned int startPos = 0; + size_t findPos = tmpStr.find(sep, startPos); + while (findPos != string::npos) { + if (findPos > startPos) { + res.push_back(tmpStr.substr(static_cast(startPos), static_cast((findPos - startPos)))); + } + startPos = findPos + sep.length(); + findPos = tmpStr.find(sep, startPos); + } + + if (startPos < tmpStr.length()) { + res.push_back(tmpStr.substr(startPos)); + } +} + +// the func is called for AcousticPruner and AcousticPrunerExtra file +std::vector StringUtil::StringSplit(string &str, const string &pattern) +{ + string::size_type pos; + vector result; + str += pattern; + unsigned int size = str.size(); + + for (unsigned int i = 0; i < size; i++) { + pos = str.find(pattern, i); + if (pos < size) { + string s = str.substr(i, pos - i); + result.push_back(s); + i = pos + pattern.size() - 1; + } + } + + return result; +} + +template string StringUtil::PrintVector(vector &array, string &delimiter) +{ + if (array.empty()) { + return ""; + } + + ostringstream oss; + copy(array.begin(), array.end() - 1, ostream_iterator(oss, delimiter.c_str())); + oss << array.back(); + + return oss.str(); +} + +void StringUtil::TrimSpecialChars(string &str) +{ + size_t sp = 0; + + while (sp < str.size()) { + size_t ep = str.find_first_of(" \t\n\v\f\r,.:;!~@#$%^&*()`?/-+", sp); + if (ep != string::npos) { + str.erase(ep, 1); + sp = ep; + } else { + break; + } + } +} + +uint32_t StringUtil::CalSubStrNum(const string &str, const string &subStr) +{ + if (subStr.size() == 0) { + return 0; + } + uint32_t count = 0; + string::size_type pos = 0; + pos = str.find(subStr, pos); + while (pos != string::npos) { + count++; + pos = pos + subStr.size(); + pos = str.find(subStr, pos); + } + + return count; +} +bool StringUtil::SplitLineToPair(const std::string &line, std::string &first, std::string &second) +{ + if (line.empty()) { + INTELL_VOICE_LOG_ERROR("line is empty"); + return false; + } + // pinyin:words + size_t pos = line.find(DELIMITER_EQUAL_SIGN); + // not find delimiter or it is the last char. + if (string::npos == pos || (line.length() - 1) == pos) { + return false; + } + + first = line.substr(0, pos); + second = line.substr(pos + 1, string::npos); + // trim left and right spaces. + Trim(first); + Trim(second); + + if (first.empty() || second.empty()) { + INTELL_VOICE_LOG_ERROR("line is invalid, first:%s, second:%s", first.c_str(), second.c_str()); + return false; + } + return true; +} +} +} + diff --git a/utils/string_util.h b/utils/string_util.h new file mode 100755 index 0000000..dca1324 --- /dev/null +++ b/utils/string_util.h @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#ifndef STRING_UTIL_H +#define STRING_UTIL_H + +#include +#include +#include +#include "nocopyable.h" +#include "securec.h" + +namespace OHOS { +namespace IntellVoiceUtils { +class StringUtil { +public: + StringUtil() {} + ~StringUtil() {} + static void Split(const std::string &str, const std::string &sep, std::vector &res); + static std::vector StringSplit(std::string &str, const std::string &pattern); + static void TrimL(std::string &str); + static void TrimR(std::string &str); + static void Trim(std::string &str); + template static std::string PrintVector(std::vector &array, std::string &delimiter); + static std::string Float2String(float arg, int32_t precision = 6); + static std::string Int2String(int32_t arg); + static void StringToLower(std::string &str); + static std::string StringToUpper(const std::string &str); + static std::string StringToUpperX(const std::string &str); + static void TrimSpecialChars(std::string &str); + static uint32_t CalSubStrNum(const std::string &str, const std::string &subStr); + static bool SplitLineToPair(const std::string &line, std::string &first, std::string &second); + +private: + DISALLOW_COPY_AND_MOVE(StringUtil); +}; + +// remove space of left side, ascii +inline void StringUtil::TrimL(std::string &str) +{ + size_t p = str.find_first_not_of(" \t\n\v\f\r"); + if (p == std::string::npos) { + str.clear(); + } else { + str = str.substr(p); + } +} + +// remove space of right side, ascii +inline void StringUtil::TrimR(std::string &str) +{ + size_t p = str.find_last_not_of(" \t\n\v\f\r"); + if (p == std::string::npos) { + str.clear(); + } else { + str.erase(p + 1); + } +} + +// remove space of both side, ascii +inline void StringUtil::Trim(std::string &str) +{ + TrimL(str); + TrimR(str); +} + +inline std::string StringUtil::Float2String(float arg, int32_t precision) +{ + // warning -- local variable 'score' declared not subsequently referenced is false alarm, ignore + char score[100] = {'\0'}; //lint !e529 + if (sprintf_s(score, sizeof(score), "%.*f", precision, arg) == -1) { + return ""; + } + + return std::string(score); +} + +inline std::string StringUtil::Int2String(int32_t arg) +{ + static const int32_t RPESICION = 9; + std::stringstream ss; + + ss.precision(RPESICION); + ss << arg; + + return ss.str(); +} + +inline void StringUtil::StringToLower(std::string &str) +{ + for (uint32_t k = 0; k < str.size(); k++) { + str[k] = static_cast(tolower(str[k])); + } +} + +inline std::string StringUtil::StringToUpper(const std::string &str) +{ + std::string upstr = str; + for (uint32_t k = 0; k < str.size(); k++) { + upstr[k] = static_cast(toupper(str[k])); + } + + return upstr; +} + +inline std::string StringUtil::StringToUpperX(const std::string &str) +{ + std::string upstr = str; + for (uint32_t i = 0; i < upstr.size(); i++) { + if (upstr[i] <= 'z' && upstr[i] >= 'a') { + upstr[i] -= 32; // 32 is the difference between lowercase and uppercase ASCII + } + } + + return upstr; +} +} +} +#endif diff --git a/utils/time_util.cpp b/utils/time_util.cpp new file mode 100755 index 0000000..e992447 --- /dev/null +++ b/utils/time_util.cpp @@ -0,0 +1,183 @@ +/* + * 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. + */ +#include "time_util.h" +#include +#include +#include +#include +#include +#include +#include "intell_voice_log.h" + +#define LOG_TAG "TimeUtil" + +using namespace std; +static const int INVALID_TIME_T = -1; + +namespace OHOS { +namespace IntellVoiceUtils { +AutoTimer::AutoTimer() +{ + Reset(); +} + +AutoTimer::AutoTimer(const std::string &logInfo) : mLogInfo(logInfo) +{ + Reset(); +} + +AutoTimer::~AutoTimer() +{ + if (mIsReset) { + PrintTimeElapse(); + } +} + +void AutoTimer::PrintTimeElapse() +{ + PrintTimeElapse(mLogInfo); +} + +void AutoTimer::PrintTimeElapse(const std::string &logInfo) +{ + std::string log; + + try { + if (!logInfo.empty()) { + log += logInfo + " "; + } else { + log += mLogInfo + " "; + } + + std::ostringstream ss; + ss << TimeElapseMs(); + log += "time elapse: " + ss.str() + "ms"; + } catch (const std::length_error& err) { + INTELL_VOICE_LOG_ERROR("length error"); + return; + } + + INTELL_VOICE_LOG_DEBUG("%s, %s", __FUNCTION__, log.c_str()); + + mIsReset = false; +} + +void AutoTimer::Reset() +{ + TimeUtil::GetTime(mTimeStart); + mIsReset = true; +} + +long AutoTimer::TimeElapseUs() +{ + mIsReset = false; + + timespec timeEnd; + TimeUtil::GetTime(timeEnd); + + return TimeUtil::TimeElapseUs(mTimeStart, timeEnd); +} + +uint32_t AutoTimer::TimeElapseMs() +{ + return TimeElapseUs() / MS_PER_US; +} + +uint32_t AutoTimer::TimeElapseS() +{ + return TimeElapseUs() / (S_PER_MS * MS_PER_US); +} + +string TimeUtil::GetCurrTime(TimeFormat format) +{ + time_t rawTime; + struct tm *timeInfo = nullptr; + char buffer[100] = { 0 }; + + time(&rawTime); + timeInfo = localtime(&rawTime); + if (timeInfo != nullptr) { + if (format == TIME_FORMAT_DEFAULT) { + strftime(buffer, sizeof(buffer), "%Y_%m_%d_%H_%M_%S_", timeInfo); + } else if (format == TIME_FORMAT_CONTINOUS) { + strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", timeInfo); + } else if (format == TIME_FORMAT_STANDARD) { + strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeInfo); + } else { + INTELL_VOICE_LOG_WARN("invalid format:%d", format); + } + } + std::string str(buffer); + + return str; +} + +string TimeUtil::GetCurrTimeUs() +{ + struct timeval tv; + char buffer[100] = {0}; + if (gettimeofday(&tv, nullptr) == -1) { + INTELL_VOICE_LOG_ERROR("get time of day error"); + return ""; + } + struct tm *timeInfo = localtime(&tv.tv_sec); + if (timeInfo != nullptr) { + strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", timeInfo); + } + string str(buffer); + stringstream ss; + ss << tv.tv_usec; + str += ss.str(); + return str; +} + +time_t TimeUtil::GetFormatTimeToSec(const string &formatTime) +{ + INTELL_VOICE_LOG_DEBUG("GetFormatTimeToSec, formatTime is %s", formatTime.c_str()); + struct tm s_tm; + + if (!strptime(formatTime.c_str(), "%Y%m%d%H%M%S", &s_tm)) { + INTELL_VOICE_LOG_ERROR("get file create time error"); + return INVALID_TIME_T; + } + + return mktime(&s_tm); +} + +bool TimeUtil::IsFormatTimeExpired(const string &formatTime, int maxKeepTime) +{ + time_t currentTime; + time_t originalTime; + + currentTime = time(nullptr); + originalTime = GetFormatTimeToSec(formatTime); + INTELL_VOICE_LOG_DEBUG("IsFormatTimeExpired, originalTime is %ld, currentTime is %ld, maxKeepTime is %d", + originalTime, currentTime, maxKeepTime); + + if ((originalTime == INVALID_TIME_T) || (currentTime == INVALID_TIME_T)) { + INTELL_VOICE_LOG_ERROR("get sys time error"); + return false; + } + + return (currentTime >= originalTime) && (currentTime - originalTime >= maxKeepTime); +} + +uint64_t TimeUtil::GetCurrentTimeMs() +{ + return static_cast(std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()).count()); +} +} +} diff --git a/utils/time_util.h b/utils/time_util.h new file mode 100755 index 0000000..94d4cd5 --- /dev/null +++ b/utils/time_util.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 + * + * 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. + */ +#ifndef TIME_UTIL_H +#define TIME_UTIL_H + +#include +#include +#include "base_constants.h" + +namespace OHOS { +namespace IntellVoiceUtils { +enum TimeFormat { + TIME_FORMAT_DEFAULT = 0, + TIME_FORMAT_CONTINOUS, + TIME_FORMAT_STANDARD, + TIME_FORMAT_NUM +}; + +class AutoTimer { +public: + AutoTimer(); + explicit AutoTimer(const std::string &logInfo); + virtual ~AutoTimer(); + + void PrintTimeElapse(); + void PrintTimeElapse(const std::string &logInfo); + void Reset(); + long TimeElapseUs(); + uint32_t TimeElapseMs(); + uint32_t TimeElapseS(); + +private: + + std::string mLogInfo; + timespec mTimeStart { 0, 0 }; + bool mIsReset { true }; +}; + +class TimeUtil { +public: + TimeUtil() {} + ~TimeUtil() {} + static std::string GetCurrTime(TimeFormat format = TIME_FORMAT_DEFAULT); + static std::string GetCurrTimeUs(); + static time_t GetFormatTimeToSec(const std::string &formatTime); + static bool IsFormatTimeExpired(const std::string &formatTime, int maxKeepTime); + static void GetTime(timespec &start); + static uint32_t TimeElapse(const timespec &start); + static void TimeElapse(const timespec &start, const timespec &end); + static long TimeElapseUs(const timespec &start, const timespec &end); + static uint64_t GetCurrentTimeMs(); +}; + +inline void TimeUtil::GetTime(timespec &start) +{ + if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) { + return; + } +} + +inline uint32_t TimeUtil::TimeElapse(const timespec &start) +{ + timespec current; + if (clock_gettime(CLOCK_REALTIME, ¤t) == -1) { + return 0; + } + + return (current.tv_sec > start.tv_sec) ? (current.tv_sec - start.tv_sec) : 0; +} + +inline void TimeUtil::TimeElapse(const timespec &start, const timespec &end) +{ + long secs = end.tv_sec - start.tv_sec; + long hour = secs / (H_PER_MIN * MIN_PER_S); + long min = (secs % (H_PER_MIN * MIN_PER_S)) / MIN_PER_S; + long sec = secs % MIN_PER_S; + + std::cout << hour << ":" << min << ":" << sec << std::endl; + return; +} + +inline long TimeUtil::TimeElapseUs(const timespec &start, const timespec &end) +{ + long usecs = MS_PER_US * S_PER_MS * (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / US_PER_NS; + return usecs; +} +} +} + +#endif