summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitmodules6
-rw-r--r--CMakeLists.txt21
-rw-r--r--License.txt202
-rw-r--r--README.md95
m---------afb-helpers0
m---------app-controller0
-rwxr-xr-xautobuild/agl/autobuild75
-rwxr-xr-xautobuild/linux/autobuild75
-rw-r--r--conf.d/CMakeLists.txt20
-rw-r--r--conf.d/cmake/00-debian-osconfig.cmake1
-rw-r--r--conf.d/cmake/00-default-osconfig.cmake1
-rw-r--r--conf.d/cmake/config.cmake221
-rw-r--r--conf.d/project/CMakeLists.txt20
-rw-r--r--conf.d/project/etc/CMakeLists.txt32
-rw-r--r--conf.d/project/etc/vshl-capabilities-api.json52
-rw-r--r--conf.d/wgt/config.xml.in23
-rw-r--r--htdocs/AFB.js217
-rw-r--r--htdocs/binding.css99
-rw-r--r--htdocs/binding.js276
-rw-r--r--htdocs/index.html142
-rw-r--r--src/CMakeLists.txt44
-rw-r--r--src/plugins/CMakeLists.txt153
-rw-r--r--src/plugins/TestMain.cpp20
-rw-r--r--src/plugins/VshlCapabilitiesApi.cpp411
-rw-r--r--src/plugins/VshlCapabilitiesApi.h39
-rw-r--r--src/plugins/afb/AFBApiImpl.cpp78
-rw-r--r--src/plugins/afb/AFBApiImpl.h61
-rw-r--r--src/plugins/afb/AFBRequestImpl.cpp37
-rw-r--r--src/plugins/afb/AFBRequestImpl.h49
-rw-r--r--src/plugins/afb/include/AFBEventImpl.h77
-rw-r--r--src/plugins/afb/src/AFBEventImpl.cpp89
-rwxr-xr-xsrc/plugins/agreement.sh43
-rw-r--r--src/plugins/capabilities/CapabilitiesFactory.cpp71
-rw-r--r--src/plugins/capabilities/CapabilitiesFactory.h69
-rw-r--r--src/plugins/capabilities/CapabilityMessagingService.cpp117
-rw-r--r--src/plugins/capabilities/CapabilityMessagingService.h82
-rw-r--r--src/plugins/capabilities/communication/include/PhoneControlCapability.h57
-rw-r--r--src/plugins/capabilities/communication/include/PhoneControlMessages.h208
-rw-r--r--src/plugins/capabilities/communication/src/PhoneControlCapability.cpp52
-rw-r--r--src/plugins/capabilities/core/include/MessageChannel.h68
-rw-r--r--src/plugins/capabilities/core/include/PublisherForwarder.h73
-rw-r--r--src/plugins/capabilities/core/include/SubscriberForwarder.h84
-rw-r--r--src/plugins/capabilities/core/src/MessageChannel.cpp51
-rw-r--r--src/plugins/capabilities/core/src/PublisherForwarder.cpp69
-rw-r--r--src/plugins/capabilities/core/src/SubscriberForwarder.cpp139
-rw-r--r--src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h57
-rw-r--r--src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h59
-rw-r--r--src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp52
-rw-r--r--src/plugins/capabilities/navigation/include/NavigationCapability.h57
-rw-r--r--src/plugins/capabilities/navigation/include/NavigationMessages.h56
-rw-r--r--src/plugins/capabilities/navigation/src/NavigationCapability.cpp52
-rw-r--r--src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h57
-rw-r--r--src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h64
-rw-r--r--src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp52
-rw-r--r--src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp96
-rw-r--r--src/plugins/capabilities/test/PublisherForwarderTest.cpp116
-rw-r--r--src/plugins/capabilities/test/SubscriberForwarderTest.cpp262
-rw-r--r--src/plugins/cmake/gtest.cmake44
-rw-r--r--src/plugins/interfaces/afb/IAFBApi.h98
-rw-r--r--src/plugins/interfaces/capabilities/ICapability.h58
-rw-r--r--src/plugins/interfaces/utilities/events/IEventFilter.h46
-rw-r--r--src/plugins/interfaces/utilities/logging/ILogger.h42
-rw-r--r--src/plugins/test/common/ConsoleLogger.cpp31
-rw-r--r--src/plugins/test/common/ConsoleLogger.h37
-rw-r--r--src/plugins/test/mocks/AFBApiMock.h41
-rw-r--r--src/plugins/test/mocks/AFBEventMock.h47
-rw-r--r--src/plugins/test/mocks/AFBRequestMock.h33
-rw-r--r--src/plugins/test/mocks/CapabilityMock.h35
-rw-r--r--src/plugins/utilities/events/EventRouter.cpp68
-rw-r--r--src/plugins/utilities/events/EventRouter.h66
-rw-r--r--src/plugins/utilities/logging/Logger.cpp56
-rw-r--r--src/plugins/utilities/logging/Logger.h53
-rw-r--r--src/vshl-capabilities-apidef.h53
-rw-r--r--src/vshl-capabilities-apidef.json109
-rw-r--r--src/vshl-capabilities-binding.c126
-rw-r--r--src/vshl-capabilities-binding.h25
-rwxr-xr-xtools/pre-commit140
77 files changed, 6007 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..91b4a80
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "app-controller"]
+ path = app-controller
+ url = https://gerrit.automotivelinux.org/gerrit/apps/app-controller-submodule
+[submodule "afb-helpers"]
+ path = afb-helpers
+ url = https://gerrit.automotivelinux.org/gerrit/apps/app-afb-helpers-submodule
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..f39acc4
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,21 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Romain Forlot <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.5.1)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,202 @@
+
+ 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
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this 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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2a4a265
--- /dev/null
+++ b/README.md
@@ -0,0 +1,95 @@
+# 1. High Level Voice Service Capabilities (VSHL-CAPABILITIES)
+This repository hosts the code for the AGL's high level voice service's capabilities publish/subscribe binding also known as VSHL-CAPABILITIES.
+Please refer to the [architecture](https://confluence.automotivelinux.org/display/SPE/Speech+EG+Architecture) for more information.
+
+# 2. Build Dependencies and License Information
+
+During the build time, the following dependencies are fetched and run by the build system. Please refer to each of the individual entities for the particular licenses.
+* [Google Test v1.8.0](https://github.com/google/googletest) when compiled with ENABLE_UNIT_TESTS option.
+
+# 3. Getting the Source Code
+```
+export MY_PROJECTS_DIR = <Your Project Directory>
+pushd $MY_PROJECTS_DIR
+git clone --recursive https://gerrit.automotivelinux.org/gerrit/apps/agl-service-voice-high-capabilities
+```
+
+# 4. Renesas R-Car M3 board
+## 4.1 Building VSHL Capabilities
+
+```
+pushd agl-service-voice-high-capabilities
+mkdir build
+pushd build
+source /opt/agl-sdk/6.0.1-aarch64/environment-setup-aarch64-agl-linux
+cmake ..
+make autobuild
+popd
+./conf.d/autobuild/agl/autobuild package
+```
+* The build output will be located at $MY_PROJECTS_DIR/agl-service-voice-high-capabilities/build/vshl-capabilities.wgt
+
+## 4.2 Running VSHL Capabilities
+```
+# afm-util install vshl-capabilities.wgt
+# afm-util start vshl-capabilities@1.0
+```
+
+# 5. Ubuntu 16.04
+## 5.1 Building VSHL Capabilities
+
+```
+pushd agl-service-voice-high--capabilities
+mkdir build
+pushd build
+cmake ..
+make autobuild
+popd
+./conf.d/autobuild/linux/autobuild package
+```
+To build the included unit tests modify the cmake step as following:
+cmake .. -DENABLE_UNIT_TESTS=ON
+
+## 5.2 Running VSHL Capabilities
+```
+afb-daemon --port=1111 --name=afb-vshl-capabilities --workdir=$MY_PROJECTS_DIR/agl-service-voice-high-capabilities/build/package --ldpaths=lib --roothttp=htdocs --token= -vvv
+```
+
+# 6. Running the Unit Tests
+## 6.1 Ubuntu 16.04
+```
+pushd agl-service-voice-high-capabilities/
+./build/src/plugins/vshl-capabilities-api_Test
+popd
+```
+
+# 7. Testing VSHL Capabilities
+* The binding can be tested by launching the HTML5 sample application that is bundled with the package in a browser.
+
+```
+http://localhost:1111
+```
+
+# 8. Contributing code
+Before contributing the source, its recommended to format the code with clang-format. This is done automatically during commit step if following instructions are followed.
+**Prerequisite**: Install clang-format-6.0 or greater.
+There are following 2 options.
+
+* Before commit, manually run clang-format on the file (It will use local .clang-format file for checking the rules)
+```
+clang-format -i <path to source file>
+```
+
+* Setup clang-format as pre-commit git hook. This is one time step after you clone the repo
+```
+cd ${VSHL_CAPABILITIES_ROOT}
+cp tools/pre-commit .git/hooks/pre-commit
+```
+
+* With the hook in place, everytime you try to commit, it will check the format and disallow commit if format doesn't abide by the .clang-format rules.
+It will also give you the option to apply a patch (it creates a patch in /tmp folder) to make the source abide by the .clang-format rules. Apply the patch and proceed to commit
+```
+git apply /tmp/<patch>
+git add <source files>
+git commit
+``` \ No newline at end of file
diff --git a/afb-helpers b/afb-helpers
new file mode 160000
+Subproject fd4fe7525aaf737597e004b0a2b7d91bf18c9f1
diff --git a/app-controller b/app-controller
new file mode 160000
+Subproject f8531f98503e72238253d4faff634293ad4d194
diff --git a/autobuild/agl/autobuild b/autobuild/agl/autobuild
new file mode 100755
index 0000000..a832db4
--- /dev/null
+++ b/autobuild/agl/autobuild
@@ -0,0 +1,75 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015 - 2018 "IoT.bzh"
+# Author "Romain Forlot" <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+
+THISFILE := $(lastword $(MAKEFILE_LIST))
+BUILD_DIR := $(abspath $(dir $(THISFILE))/../../build)
+DEST := ${BUILD_DIR}
+
+.PHONY: all clean distclean configure build package help update
+
+all: help
+
+help:
+ @echo "List of targets available:"
+ @echo ""
+ @echo "- all"
+ @echo "- clean"
+ @echo "- distclean"
+ @echo "- configure"
+ @echo "- build: compilation, link and prepare files for package into a widget"
+ @echo "- package: output a widget file '*.wgt'"
+ @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory"
+ @echo ""
+ @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt"
+ @echo "Don't use your build dir as DEST as wgt file is generated at this location"
+
+update: configure
+ @cmake --build ${BUILD_DIR} --target autobuild
+
+clean:
+ @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} ${CLEAN_ARGS} clean) || echo Nothing to clean
+
+distclean:
+ @rm -rf ${BUILD_DIR}
+
+configure:
+ @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
+ @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..)
+
+build: configure
+ @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all
+
+package: build
+ @mkdir -p ${BUILD_DIR}/$@/bin
+ @mkdir -p ${BUILD_DIR}/$@/etc
+ @mkdir -p ${BUILD_DIR}/$@/lib
+ @mkdir -p ${BUILD_DIR}/$@/htdocs
+ @mkdir -p ${BUILD_DIR}/$@/var
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target widget
+ @mkdir -p ${DEST} && cp ${BUILD_DIR}/*.wgt ${DEST}
+
+package-test: build
+ @mkdir -p ${BUILD_DIR}/$@/bin
+ @mkdir -p ${BUILD_DIR}/$@/etc
+ @mkdir -p ${BUILD_DIR}/$@/lib
+ @mkdir -p ${BUILD_DIR}/$@/htdocs
+ @mkdir -p ${BUILD_DIR}/$@/var
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target widget
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target test_widget
+ @mkdir -p ${DEST} && cp ${BUILD_DIR}/*.wgt ${DEST}
+
+install: build
+ @cmake --build ${BUILD_DIR} ${INSTALL_ARGS} --target install
diff --git a/autobuild/linux/autobuild b/autobuild/linux/autobuild
new file mode 100755
index 0000000..a832db4
--- /dev/null
+++ b/autobuild/linux/autobuild
@@ -0,0 +1,75 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015 - 2018 "IoT.bzh"
+# Author "Romain Forlot" <romain.forlot@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+
+THISFILE := $(lastword $(MAKEFILE_LIST))
+BUILD_DIR := $(abspath $(dir $(THISFILE))/../../build)
+DEST := ${BUILD_DIR}
+
+.PHONY: all clean distclean configure build package help update
+
+all: help
+
+help:
+ @echo "List of targets available:"
+ @echo ""
+ @echo "- all"
+ @echo "- clean"
+ @echo "- distclean"
+ @echo "- configure"
+ @echo "- build: compilation, link and prepare files for package into a widget"
+ @echo "- package: output a widget file '*.wgt'"
+ @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory"
+ @echo ""
+ @echo "Usage: ./autobuild/agl/autobuild package DEST=${HOME}/opt"
+ @echo "Don't use your build dir as DEST as wgt file is generated at this location"
+
+update: configure
+ @cmake --build ${BUILD_DIR} --target autobuild
+
+clean:
+ @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} ${CLEAN_ARGS} clean) || echo Nothing to clean
+
+distclean:
+ @rm -rf ${BUILD_DIR}
+
+configure:
+ @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
+ @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..)
+
+build: configure
+ @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all
+
+package: build
+ @mkdir -p ${BUILD_DIR}/$@/bin
+ @mkdir -p ${BUILD_DIR}/$@/etc
+ @mkdir -p ${BUILD_DIR}/$@/lib
+ @mkdir -p ${BUILD_DIR}/$@/htdocs
+ @mkdir -p ${BUILD_DIR}/$@/var
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target widget
+ @mkdir -p ${DEST} && cp ${BUILD_DIR}/*.wgt ${DEST}
+
+package-test: build
+ @mkdir -p ${BUILD_DIR}/$@/bin
+ @mkdir -p ${BUILD_DIR}/$@/etc
+ @mkdir -p ${BUILD_DIR}/$@/lib
+ @mkdir -p ${BUILD_DIR}/$@/htdocs
+ @mkdir -p ${BUILD_DIR}/$@/var
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target widget
+ @cmake --build ${BUILD_DIR} ${PACKAGE_ARGS} --target test_widget
+ @mkdir -p ${DEST} && cp ${BUILD_DIR}/*.wgt ${DEST}
+
+install: build
+ @cmake --build ${BUILD_DIR} ${INSTALL_ARGS} --target install
diff --git a/conf.d/CMakeLists.txt b/conf.d/CMakeLists.txt
new file mode 100644
index 0000000..3beb009
--- /dev/null
+++ b/conf.d/CMakeLists.txt
@@ -0,0 +1,20 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <rfulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+# This component should be included as a submodule and wont compile as standalone
+project_subdirs_add()
diff --git a/conf.d/cmake/00-debian-osconfig.cmake b/conf.d/cmake/00-debian-osconfig.cmake
new file mode 100644
index 0000000..2ce0ad3
--- /dev/null
+++ b/conf.d/cmake/00-debian-osconfig.cmake
@@ -0,0 +1 @@
+list(APPEND PKG_REQUIRED_LIST lua-5.3>=5.3)
diff --git a/conf.d/cmake/00-default-osconfig.cmake b/conf.d/cmake/00-default-osconfig.cmake
new file mode 100644
index 0000000..a2b9325
--- /dev/null
+++ b/conf.d/cmake/00-default-osconfig.cmake
@@ -0,0 +1 @@
+list(APPEND PKG_REQUIRED_LIST lua>=5.3)
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
new file mode 100644
index 0000000..da2ce59
--- /dev/null
+++ b/conf.d/cmake/config.cmake
@@ -0,0 +1,221 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Sebastien Douheret <sebastien@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+# Project Info
+# ------------------
+set(PROJECT_NAME vshl-capabilities)
+set(PROJECT_VERSION "0.1")
+set(PROJECT_PRETTY_NAME "High Level Voice Service capabilities APIs")
+set(PROJECT_DESCRIPTION "Binding that provides high level voice service capabilities subscribe and publish APIs to AGL apps.")
+set(PROJECT_ICON "icon.png")
+set(PROJECT_AUTHOR "Naveen Bobbili")
+set(PROJECT_AUTHOR_MAIL "nbobbili@amazon.com")
+set(PROJECT_LICENSE "APL2.0")
+set(PROJECT_LANGUAGES "CXX")
+
+# Where are stored the project configuration files
+# relative to the root project directory
+set(PROJECT_CMAKE_CONF_DIR "conf.d")
+
+# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
+# but used and must be built and linked.
+# set(PROJECT_LIBDIR "libs")
+
+# Which directories inspect to find CMakeLists.txt target files
+# set(PROJECT_SRC_DIR_PATTERN "*")
+
+# Compilation Mode (DEBUG, RELEASE)
+# ----------------------------------
+set(CMAKE_BUILD_TYPE "RELEASE")
+#set(USE_EFENCE 1)
+
+# Helpers Submodule parameters
+# set(AFB_HELPERS_QTWSCLIENT OFF CACHE BOOL "Adds QT5 WebSocket helpers from submodule")
+
+# Kernel selection if needed. You can choose between a
+# mandatory version to impose a minimal version.
+# Or check Kernel minimal version and just print a Warning
+# about missing features and define a preprocessor variable
+# to be used as preprocessor condition in code to disable
+# incompatibles features. Preprocessor define is named
+# KERNEL_MINIMAL_VERSION_OK.
+#
+# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and
+# Yocto SDK Kernel version.
+# -----------------------------------------------
+#set (kernel_mandatory_version 4.8)
+#set (kernel_minimal_version 4.8)
+
+# Compiler selection if needed. Impose a minimal version.
+# -----------------------------------------------
+set (gcc_minimal_version 4.9)
+
+# PKG_CONFIG required packages
+# -----------------------------
+set (PKG_REQUIRED_LIST
+ json-c
+ afb-daemon
+)
+
+# Prefix path where will be installed the files
+# Default: /usr/local (need root permission to write in)
+# ------------------------------------------------------
+#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
+
+# Customize link option
+# -----------------------------
+#list(APPEND link_libraries -an-option)
+
+# Compilation options definition
+# Use CMake generator expressions to specify only for a specific language
+# Values are prefilled with default options that is currently used.
+# Either separate options with ";", or each options must be quoted separately
+# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED !
+# ----------------------------------------------------------------------------
+set(COMPILE_OPTIONS
+ -Wno-missing-field-initializers
+ -Wno-format-security
+# -Wall
+# -Wextra
+# -Wconversion
+# -Wno-unused-parameter
+# -Wno-sign-compare
+# -Wno-sign-conversion
+# -Werror=maybe-uninitialized
+# -Werror=implicit-function-declaration
+# -ffunction-sections
+# -fdata-sections
+# -fPIC
+ CACHE STRING "Compilation flags")
+#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.")
+#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.")
+#set(PROFILING_COMPILE_OPTIONS
+# -g
+# -O0
+# -pg
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for PROFILING build type.")
+#set(DEBUG_COMPILE_OPTIONS
+# -g
+# -ggdb
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for DEBUG build type.")
+#set(CCOV_COMPILE_OPTIONS
+# -g
+# -O2
+# --coverage
+# CACHE STRING "Compilation flags for CCOV build type.")
+#set(RELEASE_COMPILE_OPTIONS
+# -g
+# -O2
+# CACHE STRING "Compilation flags for RELEASE build type.")
+
+set(CONTROL_SUPPORT_LUA 1)
+# Search Paths: Build directory -> CMake installation path -> AFM installation path
+add_definitions(-DCONTROL_PLUGIN_PATH="${CMAKE_BINARY_DIR}/package/lib/plugins:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib/plugins:/var/local/lib/afm/applications/${PROJECT_NAME}/${PROJECT_VERSION}/lib/plugins")
+add_definitions(-DCONTROL_CONFIG_PATH="${CMAKE_BINARY_DIR}/package/etc:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}:/var/local/lib/afm/applications/${PROJECT_NAME}")
+#add_definitions(-DCONTROL_LUA_PATH="${CMAKE_SOURCE_DIR}/conf.d/project/lua.d:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/var:${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}")
+add_definitions(-DCTL_PLUGIN_MAGIC=1286576532)
+add_definitions(-DUSE_API_DYN=1 -DAFB_BINDING_VERSION=3 -DAFB_BINDING_WANT_DYNAPI)
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
+# ---------------------------------------------------------------------
+#set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+#set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
+
+# Optional location for config.xml.in
+# -----------------------------------
+#set(WIDGET_ICON "\"conf.d/wgt/${PROJECT_ICON}\"" CACHE PATH "Path to the widget icon")
+set(WIDGET_CONFIG_TEMPLATE "${CMAKE_SOURCE_DIR}/conf.d/wgt/config.xml.in" CACHE PATH "Path to widget config file template (config.xml.in)")
+
+# Mandatory widget Mimetype specification of the main unit
+# --------------------------------------------------------------------------
+# Choose between :
+#- text/html : HTML application,
+# content.src designates the home page of the application
+#
+#- application/vnd.agl.native : AGL compatible native,
+# content.src designates the relative path of the binary.
+#
+# - application/vnd.agl.service: AGL service, content.src is not used.
+#
+#- ***application/x-executable***: Native application,
+# content.src designates the relative path of the binary.
+# For such application, only security setup is made.
+#
+set(WIDGET_TYPE application/vnd.agl.service)
+
+# Mandatory Widget entry point file of the main unit
+# --------------------------------------------------------------
+# This is the file that will be executed, loaded,
+# at launch time by the application framework.
+#
+set(WIDGET_ENTRY_POINT lib/afb-vshl-capabilities.so)
+
+# Optional dependencies order
+# ---------------------------
+#set(EXTRA_DEPENDENCIES_ORDER)
+
+# Optional Extra global include path
+# -----------------------------------
+#set(EXTRA_INCLUDE_DIRS)
+
+# Optional extra libraries
+# -------------------------
+#set(EXTRA_LINK_LIBRARIES)
+
+# Optional force binding installation
+# ------------------------------------
+# set(BINDINGS_INSTALL_PREFIX PrefixPath )
+
+# Optional force binding Linking flag
+# ------------------------------------
+# set(BINDINGS_LINK_FLAG LinkOptions )
+
+# Optional force package prefix generation, like widget
+# -----------------------------------------------------
+# set(PKG_PREFIX DestinationPath)
+
+# Optional Application Framework security token
+# and port use for remote debugging.
+#------------------------------------------------------------
+set(AFB_TOKEN "" CACHE PATH "Default binder security token")
+set(AFB_REMPORT "1111" CACHE PATH "Default binder listening port")
+
+# Print a helper message when every thing is finished
+# ----------------------------------------------------
+set(CLOSING_MESSAGE "Typical binding launch: \
+afb-daemon --port=${AFB_REMPORT} --name=afb-speech --workdir=${CMAKE_BINARY_DIR}/package \
+--ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" -vvv")
+
+set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
+
+# Optional schema validator about now only XML, LUA and JSON
+# are supported
+#------------------------------------------------------------
+#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler")
+#set(XML_CHECKER "xmllint" CACHE STRING "XML linter")
+#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter")
+
+# This include is mandatory and MUST happens at the end
+# of this file, else you expose you to unexpected behavior
+#
+# This CMake module could be found at the following url:
+# https://gerrit.automotivelinux.org/gerrit/#/admin/projects/src/cmake-apps-module
+# -----------------------------------------------------------
+include(CMakeAfbTemplates) \ No newline at end of file
diff --git a/conf.d/project/CMakeLists.txt b/conf.d/project/CMakeLists.txt
new file mode 100644
index 0000000..3beb009
--- /dev/null
+++ b/conf.d/project/CMakeLists.txt
@@ -0,0 +1,20 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <rfulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+# This component should be included as a submodule and wont compile as standalone
+project_subdirs_add()
diff --git a/conf.d/project/etc/CMakeLists.txt b/conf.d/project/etc/CMakeLists.txt
new file mode 100644
index 0000000..fc44330
--- /dev/null
+++ b/conf.d/project/etc/CMakeLists.txt
@@ -0,0 +1,32 @@
+###########################################################################
+# Copyright 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+##################################################
+# Control Policy Config file
+##################################################
+PROJECT_TARGET_ADD(vshl-capabilities-api-config)
+
+ file(GLOB CONF_FILES "*.json")
+
+ add_input_files("${CONF_FILES}")
+
+ SET_TARGET_PROPERTIES(
+ ${TARGET_NAME} PROPERTIES
+ LABELS "BINDING-CONFIG"
+ OUTPUT_NAME ${TARGET_NAME}
+ ) \ No newline at end of file
diff --git a/conf.d/project/etc/vshl-capabilities-api.json b/conf.d/project/etc/vshl-capabilities-api.json
new file mode 100644
index 0000000..04706b0
--- /dev/null
+++ b/conf.d/project/etc/vshl-capabilities-api.json
@@ -0,0 +1,52 @@
+{
+ "$schema": "http://iot.bzh/download/public/schema/json/ctl-schema.json",
+ "metadata": {
+ "uid": "vshl-capabilities",
+ "version": "0.1",
+ "api": "vshl-capabilities",
+ "info": "High Level Voice Service Capabilities APIs"
+ },
+
+ "plugins": [{
+ "uid": "vshl-capabilities",
+ "info": "Plugin to handle high level voice service capabilities API implementation",
+ "libs": [
+ "vshl-capabilities-api.ctlso"
+ ]
+ }],
+
+
+ "controls": [{
+ "uid": "guiMetadata/publish",
+ "privileges": "urn:AGL:permission:vshl-capabilities:guiMetadata:public",
+ "action": "plugin://vshl-capabilities#guiMetadataPublish"
+ }, {
+ "uid": "guiMetadata/subscribe",
+ "privileges": "urn:AGL:permission:vshl-capabilities:guiMetadata:public",
+ "action": "plugin://vshl-capabilities#guiMetadataSubscribe"
+ }, {
+ "uid": "phonecontrol/publish",
+ "privileges": "urn:AGL:permission:vshl-capabilities:phonecontrol:public",
+ "action": "plugin://vshl-capabilities#phonecontrolPublish"
+ }, {
+ "uid": "phonecontrol/subscribe",
+ "privileges": "urn:AGL:permission:vshl-capabilities:phonecontrol:public",
+ "action": "plugin://vshl-capabilities#phonecontrolSubscribe"
+ }, {
+ "uid": "navigation/publish",
+ "privileges": "urn:AGL:permission:vshl-capabilities:navigation:public",
+ "action": "plugin://vshl-capabilities#navigationPublish"
+ }, {
+ "uid": "navigation/subscribe",
+ "privileges": "urn:AGL:permission:vshl-capabilities:navigation:public",
+ "action": "plugin://vshl-capabilities#navigationSubscribe"
+ }, {
+ "uid": "playbackcontroller/publish",
+ "privileges": "urn:AGL:permission:vshl-capabilities:playbackcontroller:public",
+ "action": "plugin://vshl-capabilities#playbackControllerPublish"
+ }, {
+ "uid": "playbackcontroller/subscribe",
+ "privileges": "urn:AGL:permission:vshl-capabilities:playbackcontroller:public",
+ "action": "plugin://vshl-capabilities#playbackControllerSubscribe"
+ }]
+} \ No newline at end of file
diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in
new file mode 100644
index 0000000..fed5bdf
--- /dev/null
+++ b/conf.d/wgt/config.xml.in
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="0.1">
+ <name>@PROJECT_NAME@</name>
+ <icon src="@PROJECT_ICON@"/>
+ <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/>
+ <description>@PROJECT_DESCRIPTION@</description>
+ <author>@PROJECT_AUTHOR@ &lt;@PROJECT_AUTHOR_MAIL@&gt;</author>
+ <license>@PROJECT_LICENSE@</license>
+ <feature name="urn:AGL:widget:provided-api">
+ <param name="vshl-capabilities" value="ws" />
+ </feature>
+ <feature name="urn:AGL:widget:required-binding">
+ <param name="@WIDGET_ENTRY_POINT@" value="local" />
+ </feature>
+ <feature name="urn:AGL:widget:required-api">
+ <param name="afm-main" value="ws" />
+ <param name="homescreen" value="ws" />
+ </feature>
+ <feature name="urn:AGL:widget:required-permission">
+ <param name="urn:AGL:permission::public:hidden" value="required" />
+ </feature>
+
+</widget> \ No newline at end of file
diff --git a/htdocs/AFB.js b/htdocs/AFB.js
new file mode 100644
index 0000000..2cf3aec
--- /dev/null
+++ b/htdocs/AFB.js
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2017, 2018 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this 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.
+ */
+AFB = function(base, initialtoken){
+
+if (typeof base != "object")
+ base = { base: base, token: initialtoken };
+
+var initial = {
+ base: base.base || "api",
+ token: base.token || initialtoken || "HELLO",
+ host: base.host || window.location.host,
+ url: base.url || undefined
+};
+
+var urlws = initial.url || "ws://"+initial.host+"/"+initial.base;
+
+/*********************************************/
+/**** ****/
+/**** AFB_context ****/
+/**** ****/
+/*********************************************/
+var AFB_context;
+{
+ var UUID = undefined;
+ var TOKEN = initial.token;
+
+ var context = function(token, uuid) {
+ this.token = token;
+ this.uuid = uuid;
+ }
+
+ context.prototype = {
+ get token() {return TOKEN;},
+ set token(tok) {if(tok) TOKEN=tok;},
+ get uuid() {return UUID;},
+ set uuid(id) {if(id) UUID=id;}
+ };
+
+ AFB_context = new context();
+}
+/*********************************************/
+/**** ****/
+/**** AFB_websocket ****/
+/**** ****/
+/*********************************************/
+var AFB_websocket;
+{
+ var CALL = 2;
+ var RETOK = 3;
+ var RETERR = 4;
+ var EVENT = 5;
+
+ var PROTO1 = "x-afb-ws-json1";
+
+ AFB_websocket = function(on_open, on_abort) {
+ var u = urlws, p = '?';
+ if (AFB_context.token) {
+ u = u + '?x-afb-token=' + AFB_context.token;
+ p = '&';
+ }
+ if (AFB_context.uuid)
+ u = u + p + 'x-afb-uuid=' + AFB_context.uuid;
+ this.ws = new WebSocket(u, [ PROTO1 ]);
+ this.url = u;
+ this.pendings = {};
+ this.awaitens = {};
+ this.counter = 0;
+ this.ws.onopen = onopen.bind(this);
+ this.ws.onerror = onerror.bind(this);
+ this.ws.onclose = onclose.bind(this);
+ this.ws.onmessage = onmessage.bind(this);
+ this.onopen = on_open;
+ this.onabort = on_abort;
+ }
+
+ function onerror(event) {
+ var f = this.onabort;
+ if (f) {
+ delete this.onopen;
+ delete this.onabort;
+ f(this);
+ }
+ this.onerror && this.onerror(this);
+ }
+
+ function onopen(event) {
+ var f = this.onopen;
+ delete this.onopen;
+ delete this.onabort;
+ f && f(this);
+ }
+
+ function onclose(event) {
+ var err = {
+ jtype: 'afb-reply',
+ request: {
+ status: 'disconnected',
+ info: 'server hung up'
+ }
+ };
+ for (var id in this.pendings) {
+ try { this.pendings[id][1](err); } catch (x) {/*NOTHING*/}
+ }
+ this.pendings = {};
+ this.onclose && this.onclose();
+ }
+
+ function fire(awaitens, name, data) {
+ var a = awaitens[name];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ var i = name.indexOf("/");
+ if (i >= 0) {
+ a = awaitens[name.substring(0,i)];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ }
+ a = awaitens["*"];
+ if (a)
+ a.forEach(function(handler){handler(data);});
+ }
+
+ function reply(pendings, id, ans, offset) {
+ if (id in pendings) {
+ var p = pendings[id];
+ delete pendings[id];
+ try { p[offset](ans); } catch (x) {/*TODO?*/}
+ }
+ }
+
+ function onmessage(event) {
+ var obj = JSON.parse(event.data);
+ var code = obj[0];
+ var id = obj[1];
+ var ans = obj[2];
+ AFB_context.token = obj[3];
+ switch (code) {
+ case RETOK:
+ reply(this.pendings, id, ans, 0);
+ break;
+ case RETERR:
+ reply(this.pendings, id, ans, 1);
+ break;
+ case EVENT:
+ default:
+ fire(this.awaitens, id, ans);
+ break;
+ }
+ }
+
+ function close() {
+ this.ws.close();
+ this.ws.onopen =
+ this.ws.onerror =
+ this.ws.onclose =
+ this.ws.onmessage =
+ this.onopen =
+ this.onabort = function(){};
+ }
+
+ function call(method, request, callid) {
+ return new Promise((function(resolve, reject){
+ var id, arr;
+ if (callid) {
+ id = String(callid);
+ if (id in this.pendings)
+ throw new Error("pending callid("+id+") exists");
+ } else {
+ do {
+ id = String(this.counter = 4095 & (this.counter + 1));
+ } while (id in this.pendings);
+ }
+ this.pendings[id] = [ resolve, reject ];
+ arr = [CALL, id, method, request ];
+ if (AFB_context.token) arr.push(AFB_context.token);
+ this.ws.send(JSON.stringify(arr));
+ }).bind(this));
+ }
+
+ function onevent(name, handler) {
+ var id = name;
+ var list = this.awaitens[id] || (this.awaitens[id] = []);
+ list.push(handler);
+ }
+
+ AFB_websocket.prototype = {
+ close: close,
+ call: call,
+ onevent: onevent
+ };
+}
+/*********************************************/
+/**** ****/
+/**** ****/
+/**** ****/
+/*********************************************/
+return {
+ context: AFB_context,
+ ws: AFB_websocket,
+ url: urlws
+};
+};
+
diff --git a/htdocs/binding.css b/htdocs/binding.css
new file mode 100644
index 0000000..9ee1303
--- /dev/null
+++ b/htdocs/binding.css
@@ -0,0 +1,99 @@
+body.page-content {
+ height: 100%;
+ width: auto;
+ margin-top: 20px;
+ background-size: cover;
+ background-position: center;
+}
+
+img {
+ float: right;
+}
+
+ol {
+ display: flex;
+ flex-direction: column;
+}
+
+#question,
+#output,
+#outevt {
+ white-space: pre-wrap;
+}
+
+div.row {
+ display: flex;
+ flex-direction: row;
+}
+
+div.col1 {
+ flex-basis: 0;
+ flex-grow: 1;
+ width: 100%;
+}
+
+div.col2 {
+ flex-basis: 0;
+ flex-grow: 1;
+ width: 30ch;
+}
+
+button {
+ margin-right: 10px;
+ padding: 6px 8px;
+ font-size: large;
+}
+
+pre {
+ outline: 1px solid #ccc;
+ padding: 5px;
+ margin: 5px;
+ background-color: white;
+ opacity: 0.85;
+ min-height: 5pc;
+ max-height: 5pc;
+ overflow: auto;
+}
+
+.string {
+ color: green;
+}
+
+.number {
+ color: darkorange;
+}
+
+.boolean {
+ color: blue;
+}
+
+.null {
+ color: magenta;
+}
+
+.key {
+ color: red;
+}
+
+dialog {
+ padding: 0;
+ border: 0;
+ border-radius: 0.6rem;
+ box-shadow: 0 0 1em black;
+}
+
+dialog::backdrop {
+ /* make the backdrop a semi-transparent black */
+ background-color: rgba(0, 0, 0, 0.4);
+}
+
+h3.dialogheader {
+ background-color: lightgreen;
+ padding: 1ch;
+}
+
+footer {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+} \ No newline at end of file
diff --git a/htdocs/binding.js b/htdocs/binding.js
new file mode 100644
index 0000000..9de9608
--- /dev/null
+++ b/htdocs/binding.js
@@ -0,0 +1,276 @@
+var afbVshlCapabilities;
+var ws;
+var evtIdx = 0;
+var count = 0;
+
+//**********************************************
+// Logger
+//**********************************************
+var log = {
+ command: function (url, api, verb, query) {
+ console.log("subscribe api=" + api + " verb=" + verb + " query=", query);
+ var question = url + "/" + api + "/" + verb + "?query=" + JSON.stringify(query);
+ log._write("question", count + ": " + log.syntaxHighlight(question));
+ },
+
+ event: function (obj) {
+ console.log("gotevent:" + JSON.stringify(obj));
+ log._write("outevt", (evtIdx++) + ": " + JSON.stringify(obj));
+ },
+
+ reply: function (obj) {
+ console.log("replyok:" + JSON.stringify(obj));
+ log._write("output", count + ": OK: " + log.syntaxHighlight(obj));
+ },
+
+ error: function (obj) {
+ console.log("replyerr:" + JSON.stringify(obj));
+ log._write("output", count + ": ERROR: " + log.syntaxHighlight(obj));
+ },
+
+ _write: function (element, msg) {
+ var el = document.getElementById(element);
+ el.innerHTML += msg + '\n';
+
+ // auto scroll down
+ setTimeout(function () {
+ el.scrollTop = el.scrollHeight;
+ }, 100);
+ },
+
+ syntaxHighlight: function (json) {
+ if (typeof json !== 'string') {
+ json = JSON.stringify(json, undefined, 2);
+ }
+ json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
+ var cls = 'number';
+ if (/^"/.test(match)) {
+ if (/:$/.test(match)) {
+ cls = 'key';
+ } else {
+ cls = 'string';
+ }
+ } else if (/true|false/.test(match)) {
+ cls = 'boolean';
+ } else if (/null/.test(match)) {
+ cls = 'null';
+ }
+ return '<span class="' + cls + '">' + match + '</span>';
+ });
+ },
+};
+
+//**********************************************
+// Generic function to call binder
+//***********************************************
+function callbinder(url, api, verb, query) {
+ log.command(url, api, verb, query);
+
+ // ws.call return a Promise
+ return ws.call(api + '/' + verb, query)
+ .then(function (res) {
+ log.reply(res);
+ count++;
+ return res;
+ })
+ .catch(function (err) {
+ log.reply(err);
+ count++;
+ throw err;
+ });
+};
+
+
+//**********************************************
+// connect - establish Websocket connection
+//**********************************************
+
+function connect(elemID, api, verb, query) {
+ connectVshlCapabilities(elemID, api, verb, query);
+}
+
+//**********************************************
+
+//
+var lastCallId;
+
+function onCapabilityEvent(eventDataObj) {
+ log.event(eventDataObj);
+ if (eventDataObj.event == "vshl-capabilities/dial") {
+ lastCallId = JSON.parse(eventDataObj.data).callId;
+ console.log("New Dial Directive received. Sending ringing state back");
+ // send ringing state back.
+ triggerCallStateChangedAction("OUTBOUND_RINGING");
+ }
+}
+
+function triggerPhoneConnectionStateChanged(newState) {
+ var paramsJson = {
+ "action" : "connection_state_changed",
+ "payload": {
+ "state" : newState
+ }
+ }
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'phonecontrol/publish', paramsJson);
+}
+
+function triggerCallStateChangedAction(newCallstate) {
+ var query = {
+ "action": "call_state_changed",
+ "payload": {
+ "callId": lastCallId,
+ "state": newCallstate
+ }
+ }
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'phonecontrol/publish', query);
+}
+
+function guid() {
+ function s4() {
+ return Math.floor((1 + Math.random()) * 0x10000)
+ .toString(16)
+ .substring(1);
+ }
+ return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
+}
+
+function triggerCallStateInBoundRingingAction() {
+ var callId = guid();
+ var state = "INBOUND_RINGING";
+ var query = {
+ "action": "call_state_changed",
+ "payload": {
+ "callId": callId,
+ "state": state
+ }
+ }
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'phonecontrol/publish', query);
+}
+
+function connectVshlCapabilities(elemID, api, verb, query) {
+
+ function onopen() {
+ document.getElementById("main").style.visibility = "visible";
+ document.getElementById("connected").innerHTML = "VSHL Capabilities Binder WS Active";
+ document.getElementById("connected").style.background = "lightgreen";
+ ws.onevent("*", onCapabilityEvent);
+ }
+
+ function onabort() {
+ document.getElementById("main").style.visibility = "hidden";
+ document.getElementById("connected").innerHTML = "Connected Closed";
+ document.getElementById("connected").style.background = "red";
+ }
+
+ var urlparams = {
+ base: "api",
+ token: "HELLO",
+ };
+ const vshlCapabilitiesAddressInput = document.getElementById('vshl-capabilities-address');
+ urlparams.host = vshlCapabilitiesAddressInput.value;
+
+ afbVshlCapabilities = new AFB(urlparams, "HELLO");
+ ws = new afbVshlCapabilities.ws(onopen, onabort);
+}
+
+function clearPre(preId) {
+ const pre = document.getElementById(preId);
+ while (pre && pre.firstChild) {
+ pre.removeChild(pre.firstChild);
+ }
+}
+
+function showTemplateUIEventChooserDialog() {
+ const modal = document.getElementById('templateui-event-chooser');
+ const subscribeBtn = document.getElementById('templateui-subscribe-btn');
+
+ subscribeBtn.addEventListener('click', (evt) => {
+ const renderTemplate = document.getElementById('render_template').checked;
+ const clearTemplate = document.getElementById('clear_template').checked;
+ const renderPlayerInfo = document.getElementById('render_player_info').checked;
+ const clearPlayerInfo = document.getElementById('clear_player_info').checked;
+
+ const query = {"actions":[]};
+
+ if (renderTemplate)
+ query.actions.push('render_template');
+ if (clearTemplate)
+ query.actions.push('clear_template');
+ if (renderPlayerInfo)
+ query.actions.push('render_player_info');
+ if (clearPlayerInfo)
+ query.actions.push('clear_player_info');
+
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'guiMetadata/subscribe', query);
+ modal.close();
+ });
+
+ // makes modal appear (adds `open` attribute)
+ modal.showModal();
+}
+
+function showPhoneControlEventChooserDialog() {
+ const modal = document.getElementById('phonecontrol-event-chooser');
+ const subscribeBtn = document.getElementById('phonecontrol-subscribe-btn');
+
+ subscribeBtn.addEventListener('click', (evt) => {
+ const dial = document.getElementById('phonecontrol-dial').checked;
+ const redial = document.getElementById('phonecontrol-redial').checked;
+ const answer = document.getElementById('phonecontrol-answer').checked;
+ const stop = document.getElementById('phonecontrol-stop').checked;
+ const sendDtmf = document.getElementById('phonecontrol-send_dtmf').checked;
+
+ const query = {"actions":[]};
+
+ if (dial)
+ query.actions.push('dial');
+ if (redial)
+ query.actions.push('redial');
+ if (answer)
+ query.actions.push('answer');
+ if (stop)
+ query.actions.push('stop');
+ if (sendDtmf)
+ query.actions.push('send_dtmf');
+
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'phonecontrol/subscribe', query);
+ modal.close();
+ });
+
+ // makes modal appear (adds `open` attribute)
+ modal.showModal();
+}
+
+function showNavigationEventCHooserDialod() {
+ const modal = document.getElementById('navigation-event-chooser');
+ const subscribeBtn = document.getElementById('navigation-subscribe-btn');
+
+ subscribeBtn.addEventListener('click', (evt) => {
+ const setDestination = document.getElementById('set_destination').checked;
+ const cancelNavigation = document.getElementById('cancel_navigation').checked;
+
+ const query = {"actions":[]};
+
+ if (setDestination)
+ query.actions.push('set_destination');
+ if (cancelNavigation)
+ query.actions.push('cancel_navigation');
+
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'navigation/subscribe', query);
+ modal.close();
+ });
+
+ // makes modal appear (adds `open` attribute)
+ modal.showModal();
+}
+
+function triggerButtonPressedAction(button) {
+ var paramsJson = {
+ "action" : "button_pressed",
+ "payload": {
+ "button" : button
+ }
+ }
+ callbinder(afbVshlCapabilities.url, 'vshl-capabilities', 'playbackcontroller/publish', paramsJson);
+} \ No newline at end of file
diff --git a/htdocs/index.html b/htdocs/index.html
new file mode 100644
index 0000000..f322881
--- /dev/null
+++ b/htdocs/index.html
@@ -0,0 +1,142 @@
+<html>
+
+<head>
+ <title>VSHL CAPABILITIES API Test</title>
+ <link rel="stylesheet" href="binding.css">
+ <script type="text/javascript" src="AFB.js"></script>
+ <script type="text/javascript" src="binding.js"></script>
+</head>
+
+<body class="page-content" onload="connect()">
+
+ <h1>Voice Service High Level Support API Tester</h1>
+
+ <button id="connected" onclick="init()">Binder WS Fail</button>
+ <button id="monitoring" onclick="window.open('/monitoring/monitor.html','_monitor_ctl')">Debug/Monitoring</a>
+ </button>
+ <button onclick="clearPre('question'); clearPre('output'); clearPre('outevt');">Clear</button> <br><br>
+ VSHL CAPABILITIES URL: <input type="text" id="vshl-capabilities-address" value="localhost:1111" onchange="connectVshlCapabilities()">
+ <br>
+ <br>
+
+ <div>
+ <P>Phone Connection Status UI</p>
+ <button onclick="triggerPhoneConnectionStateChanged('CONNECTED')">Connected</button>
+ <button onclick="triggerPhoneConnectionStateChanged('DISCONNECTED')">Disconnected</button>
+ <P>Phone Call Control Inbound Ringing UI</p>
+ <button onclick="triggerCallStateInBoundRingingAction()">Simulate Inbound Ringing</button>
+ <P>Phone Call Control UI</p>
+ <button onclick="triggerCallStateChangedAction('ACTIVE')">Accept</button>
+ <button onclick="triggerCallStateChangedAction('IDLE')">Reject</button>
+ </div>
+ <div>
+ <p>Playback Controller UI</p>
+ <button onclick="triggerButtonPressedAction('play')">play</button>
+ <button onclick="triggerButtonPressedAction('pause')">pause</button>
+ <button onclick="triggerButtonPressedAction('next')">next</button>
+ <button onclick="triggerButtonPressedAction('previous')">previous</button>
+ <button onclick="triggerButtonPressedAction('skip-forward')">skip-forward</button>
+ <button onclick="triggerButtonPressedAction('skip-backward')">skip-backward</button>
+ </div>
+
+ <dialog id="templateui-event-chooser">
+ <h3 class="dialogheader">Subscribe to the following GUI Metadata Messages</h3>
+ <div>
+ <ol>
+ <li>
+ <input type="checkbox" id="render_template" checked>
+ <label>render_template</label>
+ </li>
+ <li>
+ <input type="checkbox" id="clear_template" checked>
+ <label>clear_template</label>
+ </li>
+ <li>
+ <input type="checkbox" id="render_player_info" checked>
+ <label>render_player_info</label>
+ </li>
+ <li>
+ <input type="checkbox" id="clear_player_info" checked>
+ <label>clear_player_info</label>
+ </li>
+ </ol>
+ </div>
+ <footer>
+ <button id="templateui-subscribe-btn" type="button" style="margin: 10px">Subscribe</button>
+ </footer>
+ </dialog>
+
+ <dialog id="phonecontrol-event-chooser">
+ <h3 class="dialogheader">Subscribe to the following phone control messages</h3>
+ <div>
+ <ol>
+ <li>
+ <input type="checkbox" id="phonecontrol-dial" checked>
+ <label>phonecontrol/dial</label>
+ </li>
+ <li>
+ <input type="checkbox" id="phonecontrol-redial" checked>
+ <label>phonecontrol/redial</label>
+ </li>
+ <li>
+ <input type="checkbox" id="phonecontrol-answer" checked>
+ <label>phonecontrol/answer</label>
+ </li>
+ <li>
+ <input type="checkbox" id="phonecontrol-stop" checked>
+ <label>phonecontrol/stop</label>
+ </li>
+ <li>
+ <input type="checkbox" id="phonecontrol-send_dtmf" checked>
+ <label>phonecontrol/send_dtmf</label>
+ </li>
+ </ol>
+ </div>
+ <footer>
+ <button id="phonecontrol-subscribe-btn" type="button" style="margin: 10px">Subscribe</button>
+ </footer>
+ </dialog>
+
+ <dialog id="navigation-event-chooser">
+ <h3 class="dialogheader">Subscribe to the following navigation messages</h3>
+ <div>
+ <ol>
+ <li>
+ <input type="checkbox" id="set_destination" checked>
+ <label>set_destination</label>
+ </li>
+ <li>
+ <input type="checkbox" id="cancel_navigation" checked>
+ <label>cancel_navigation</label>
+ </li>
+ </ol>
+ </div>
+ <footer>
+ <button id="navigation-subscribe-btn" type="button" style="margin: 10px">Subscribe</button>
+ </footer>
+ </dialog>
+
+ <div id="top" class="row">
+ <div id='actions' class="col1">
+ <div>
+ <h2>VSHL CAPABILITIES APIs</h2>
+ <p>Speech framework's VSHL Capabilities APIs</p>
+ <button onclick="showTemplateUIEventChooserDialog();">Subscribe to GUI Metadata</button>
+ <button onclick="showPhoneControlEventChooserDialog();">Subscribe to Phonecontrol messages</button>
+ <button onclick="showNavigationEventCHooserDialod();">Subscribe to Navigation messages</button>
+ </div>
+
+ <div id="agentsDiv">
+ </div>
+ </div>
+
+ <div id="main" style="visibility:hidden" class="col2">
+ <ol>
+ <li>Question <pre id="question"></pre>
+ <li>Response <pre id="output"></pre>
+ <li>Events: <pre id="outevt"></pre>
+ </ol>
+ </div>
+ </div>
+
+</body>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..6bc208f
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,44 @@
+###########################################################################
+# Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+# Add target to project dependency list
+PROJECT_TARGET_ADD(vshl-capabilities)
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+
+ # Define project Targets
+ add_library(${TARGET_NAME} MODULE
+ ${TARGET_NAME}-binding.c
+ )
+
+ set(OPENAPI_DEF "${TARGET_NAME}-apidef" CACHE STRING "name and path to the JSON API definition without extension")
+
+ # Binder exposes a unique public entry point
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ PREFIX "afb-"
+ LABELS "BINDINGV3"
+ LINK_FLAGS ${BINDINGS_LINK_FLAG}
+ OUTPUT_NAME ${TARGET_NAME}
+ )
+
+ # Library dependencies (include updates automatically)
+ TARGET_LINK_LIBRARIES(${TARGET_NAME}
+ afb-helpers
+ ctl-utilities
+ ${link_libraries})
+
+add_subdirectory("plugins") \ No newline at end of file
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
new file mode 100644
index 0000000..705b13d
--- /dev/null
+++ b/src/plugins/CMakeLists.txt
@@ -0,0 +1,153 @@
+###########################################################################
+# Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this 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.
+###########################################################################
+
+PROJECT_TARGET_ADD(vshl-capabilities-api)
+
+ set(CMAKE_CXX_STANDARD 11)
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
+ set(CMAKE_CXX_EXTENSIONS OFF)
+
+ set(VSHL_CAPABILITIES_LIB_SRC
+ ${CMAKE_CURRENT_SOURCE_DIR}/VshlCapabilitiesApi.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/VshlCapabilitiesApi.h
+
+ # Interfaces
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/afb/IAFBApi.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/capabilities/ICapability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/utilities/events/IEventFilter.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/utilities/logging/ILogger.h
+
+ # AFB
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBApiImpl.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBApiImpl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBRequestImpl.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBRequestImpl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/include/AFBEventImpl.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/afb/src/AFBEventImpl.cpp
+
+ #Capabilities
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilitiesFactory.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilitiesFactory.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilityMessagingService.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilityMessagingService.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/MessageChannel.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/MessageChannel.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/PublisherForwarder.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/PublisherForwarder.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/SubscriberForwarder.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/SubscriberForwarder.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/include/PhoneControlMessages.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/include/PhoneControlCapability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/src/PhoneControlCapability.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/include/PlaybackControllerMessages.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/include/PlaybackControllerCapability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/include/NavigationMessages.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/include/NavigationCapability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/src/NavigationCapability.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/include/GuiMetadataMessages.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/include/GuiMetadataCapability.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/src/GuiMetadataCapability.cpp
+
+ #Utilities
+ ${CMAKE_CURRENT_SOURCE_DIR}/utilities/events/EventRouter.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/utilities/events/EventRouter.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/utilities/logging/Logger.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/utilities/logging/Logger.cpp
+ )
+
+ # Define targets
+ ADD_LIBRARY(${TARGET_NAME} MODULE
+ ${VSHL_CAPABILITIES_LIB_SRC}
+ )
+
+ # VSHL Capabilities plugin properties
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ LABELS "PLUGIN"
+ PREFIX ""
+ SUFFIX ".ctlso"
+ OUTPUT_NAME ${TARGET_NAME}
+ )
+
+ # Define target includes
+ TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME}
+ PUBLIC ${GLIB_PKG_INCLUDE_DIRS}
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
+ PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib"
+ )
+
+ # Library dependencies (include updates automatically)
+ TARGET_LINK_LIBRARIES(${TARGET_NAME}
+ afb-helpers
+ ${GLIB_PKG_LIBRARIES}
+ ${link_libraries}
+ )
+
+ option(ENABLE_UNIT_TESTS "Build unit tests or not" OFF)
+ if (ENABLE_UNIT_TESTS)
+ execute_process(
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/agreement.sh"
+ RESULT_VARIABLE AGREEMENT_RESULT
+ )
+ message(STATUS "Agreement Result: ${AGREEMENT_RESULT}")
+ if (${AGREEMENT_RESULT} MATCHES "1")
+ message(FATAL_ERROR "User agreement not accepted. Quitting")
+ endif()
+
+ include(cmake/gtest.cmake)
+
+ set(VSHL_CAPABILITIES_TEST_SRC ${VSHL_CAPABILITIES_LIB_SRC})
+ list(APPEND VSHL_CAPABILITIES_TEST_SRC
+ # Main
+ ${CMAKE_CURRENT_SOURCE_DIR}/TestMain.cpp
+
+ # Test common
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/common/ConsoleLogger.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/common/ConsoleLogger.cpp
+
+ # Test Mocks
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBApiMock.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBEventMock.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBRequestMock.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/CapabilityMock.h
+
+ # Capabilities
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/CapabilityMessagingServiceTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/PublisherForwarderTest.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/SubscriberForwarderTest.cpp
+ )
+
+ ADD_EXECUTABLE(${TARGET_NAME}_Test
+ ${VSHL_CAPABILITIES_TEST_SRC}
+ )
+
+ TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME}_Test
+ PUBLIC ${GLIB_PKG_INCLUDE_DIRS}
+ PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}"
+ PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib"
+ )
+
+ TARGET_LINK_LIBRARIES(${TARGET_NAME}_Test
+ afb-helpers
+ libgtest
+ libgmock
+ ${GLIB_PKG_LIBRARIES}
+ ${link_libraries}
+ )
+
+ ENABLE_TESTING()
+ ADD_TEST(VshlCapabilitiesTest ${TARGET_NAME}_Test)
+ endif() \ No newline at end of file
diff --git a/src/plugins/TestMain.cpp b/src/plugins/TestMain.cpp
new file mode 100644
index 0000000..d4fcbec
--- /dev/null
+++ b/src/plugins/TestMain.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "gtest/gtest.h"
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+} \ No newline at end of file
diff --git a/src/plugins/VshlCapabilitiesApi.cpp b/src/plugins/VshlCapabilitiesApi.cpp
new file mode 100644
index 0000000..c02fb8f
--- /dev/null
+++ b/src/plugins/VshlCapabilitiesApi.cpp
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "VshlCapabilitiesApi.h"
+
+#include <list>
+
+#include "afb/AFBApiImpl.h"
+#include "afb/AFBRequestImpl.h"
+#include "capabilities/CapabilitiesFactory.h"
+#include "capabilities/CapabilityMessagingService.h"
+#include "utilities/events/EventRouter.h"
+#include "utilities/logging/Logger.h"
+
+#include "json.hpp"
+
+using namespace std;
+
+CTLP_CAPI_REGISTER("vshlsupport-api");
+
+static std::string TAG = "vshlcapabilities::plugins::VshlCapabilitiesApi";
+
+static std::string EVENTS_JSON_ATTR_VA_ID = "va_id";
+static std::string EVENTS_JSON_ATTR_EVENTS = "events";
+
+static std::string CAPABILITIES_JSON_ATTR_ACTION = "action";
+static std::string CAPABILITIES_JSON_ATTR_ACTIONS = "actions";
+static std::string CAPABILITIES_JSON_ATTR_PAYLOAD = "payload";
+
+static std::shared_ptr<vshlcapabilities::utilities::logging::Logger> sLogger;
+static std::shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> sAfbApi;
+static std::unique_ptr<vshlcapabilities::capabilities::CapabilitiesFactory> sCapabilitiesFactory;
+static std::unique_ptr<vshlcapabilities::capabilities::CapabilityMessagingService> sCapabilityMessagingService;
+static std::unique_ptr<vshlcapabilities::utilities::events::EventRouter> sEventRouter;
+
+using json = nlohmann::json;
+using Level = vshlcapabilities::utilities::logging::Logger::Level;
+
+CTLP_ONLOAD(plugin, ret) {
+ if (plugin->api == nullptr) {
+ return -1;
+ }
+
+ // Logger
+ sLogger = vshlcapabilities::utilities::logging::Logger::create(plugin->api);
+
+ // AFB Wrapper
+ sAfbApi = vshlcapabilities::afb::AFBApiImpl::create(plugin->api);
+
+ // EventRouter
+ sEventRouter = vshlcapabilities::utilities::events::EventRouter::create(sLogger);
+ if (!sEventRouter) {
+ sLogger->log(Level::ERROR, TAG, "Failed to create EventRouter");
+ return -1;
+ }
+
+ sCapabilitiesFactory = vshlcapabilities::capabilities::CapabilitiesFactory::create(sLogger);
+ if (!sCapabilitiesFactory) {
+ sLogger->log(Level::ERROR, TAG, "Failed to create CapabilitiesFactory");
+ return -1;
+ }
+
+ sCapabilityMessagingService = vshlcapabilities::capabilities::CapabilityMessagingService::create(sLogger, sAfbApi);
+ if (!sCapabilityMessagingService) {
+ sLogger->log(Level::ERROR, TAG, "Failed to create CapabilityMessagingService");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+CTLP_CAPI(guiMetadataSubscribe, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> guMetadataCapability = sCapabilitiesFactory->getGuiMetadata();
+ if (!guMetadataCapability) {
+ sLogger->log(
+ Level::WARNING,
+ TAG,
+ "guimetadataSubscribe: Failed to "
+ "fetch guimetadata capability "
+ "object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "guimetadataSubscribe: No arguments supplied.");
+ return -1;
+ }
+
+ json subscribeJson = json::parse(json_object_to_json_string(eventJ));
+ if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataSubscribe: No events array found in subscribe json");
+ return -1;
+ }
+ list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>());
+
+ // SUbscribe this client for the guimetadata events.
+ auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request);
+ for (auto event : events) {
+ if (!sCapabilityMessagingService->subscribe(*request, guMetadataCapability, event)) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataSubscribe: Failed to subscribe to event: " + event);
+ return -1;
+ }
+ }
+
+ AFB_ReqSuccess(
+ source->request, json_object_new_string("Subscription to guimetadata events successfully completed."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(guiMetadataPublish, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> guMetadataCapability = sCapabilitiesFactory->getGuiMetadata();
+ if (!guMetadataCapability) {
+ sLogger->log(
+ Level::WARNING,
+ TAG,
+ "guimetadataPublish: Failed to fetch "
+ "guimetadata capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "guimetadataPublish: No arguments supplied.");
+ return -1;
+ }
+
+ json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str());
+ if (actionJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataPublish: No action found in publish json");
+ return -1;
+ }
+
+ std::string action = std::string(json_object_get_string(actionJ));
+ if (action.empty()) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataPublish: Invalid action input found in publish json");
+ return -1;
+ }
+
+ json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str());
+ if (payloadJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataPublish: No playload found in publish json");
+ return -1;
+ }
+
+ if (!sCapabilityMessagingService->publish(guMetadataCapability, action, payloadJ)) {
+ sLogger->log(Level::ERROR, TAG, "guimetadataPublish: Failed to publish message: " + action);
+ return -1;
+ }
+
+ AFB_ReqSuccess(source->request, json_object_new_string("Successfully published guimetadata messages."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(phonecontrolSubscribe, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> phoneControlCapability = sCapabilitiesFactory->getPhoneControl();
+ if (!phoneControlCapability) {
+ sLogger->log(Level::WARNING, TAG, "phoneControlSubscribe: Failed to fetch phone control capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "phoneControlSubscribe: No arguments supplied.");
+ return -1;
+ }
+
+ json subscribeJson = json::parse(json_object_to_json_string(eventJ));
+ if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlSubscribe: No events array found in subscribe json");
+ return -1;
+ }
+ list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>());
+
+ // SUbscribe this client for the phone call control events.
+ auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request);
+ for (auto event : events) {
+ if (!sCapabilityMessagingService->subscribe(*request, phoneControlCapability, event)) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlSubscribe: Failed to subscribe to event: " + event);
+ return -1;
+ }
+ }
+
+ AFB_ReqSuccess(
+ source->request, json_object_new_string("Subscription to phone control events successfully completed."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(phonecontrolPublish, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> phoneControlCapability = sCapabilitiesFactory->getPhoneControl();
+ if (!phoneControlCapability) {
+ sLogger->log(Level::WARNING, TAG, "phoneControlPublish: Failed to fetch navigation capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "phoneControlPublish: No arguments supplied.");
+ return -1;
+ }
+
+ json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str());
+ if (actionJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlPublish: No action found in publish json");
+ return -1;
+ }
+
+ std::string action = std::string(json_object_get_string(actionJ));
+ if (action.empty()) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlPublish: Invalid action input found in publish json");
+ return -1;
+ }
+
+ json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str());
+ if (payloadJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlPublish: No playload found in publish json");
+ return -1;
+ }
+
+ if (!sCapabilityMessagingService->publish(phoneControlCapability, action, payloadJ)) {
+ sLogger->log(Level::ERROR, TAG, "phoneControlPublish: Failed to publish message: " + action);
+ return -1;
+ }
+
+ AFB_ReqSuccess(source->request, json_object_new_string("Successfully published phone control messages."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(navigationSubscribe, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> navigationCapability = sCapabilitiesFactory->getNavigation();
+ if (!navigationCapability) {
+ sLogger->log(Level::WARNING, TAG, "navigationSubscribe: Failed to fetch navigation capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "navigationSubscribe: No arguments supplied.");
+ return -1;
+ }
+
+ json subscribeJson = json::parse(json_object_to_json_string(eventJ));
+ if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "navigationSubscribe: No events array found in subscribe json");
+ return -1;
+ }
+ list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>());
+
+ // SUbscribe this client for the navigation events.
+ auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request);
+ for (auto event : events) {
+ if (!sCapabilityMessagingService->subscribe(*request, navigationCapability, event)) {
+ sLogger->log(Level::ERROR, TAG, "navigationSubscribe: Failed to subscribe to event: " + event);
+ return -1;
+ }
+ }
+
+ AFB_ReqSuccess(
+ source->request, json_object_new_string("Subscription to navigation events successfully completed."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(navigationPublish, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> navigationCapability = sCapabilitiesFactory->getNavigation();
+ if (!navigationCapability) {
+ sLogger->log(Level::WARNING, TAG, "navigationPublish: Failed to fetch navigation capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "navigationPublish: No arguments supplied.");
+ return -1;
+ }
+
+ json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str());
+ if (actionJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "navigationPublish: No action found in publish json");
+ return -1;
+ }
+
+ std::string action = std::string(json_object_get_string(actionJ));
+ if (action.empty()) {
+ sLogger->log(Level::ERROR, TAG, "navigationPublish: Invalid action input found in publish json");
+ return -1;
+ }
+
+ json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str());
+ if (payloadJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "navigationPublish: No playload found in publish json");
+ return -1;
+ }
+
+ if (!sCapabilityMessagingService->publish(navigationCapability, action, payloadJ)) {
+ sLogger->log(Level::ERROR, TAG, "navigationPublish: Failed to publish message: " + action);
+ return -1;
+ }
+
+ AFB_ReqSuccess(source->request, json_object_new_string("Successfully published navigation messages."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(playbackControllerSubscribe, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> playbackcontrollerCapability = sCapabilitiesFactory->getPlaybackController();
+ if (!playbackcontrollerCapability) {
+ sLogger->log(Level::WARNING, TAG, "playbackControllerSubscribe: Failed to fetch playbackcontroller capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "playbackControllerSubscribe: No arguments supplied.");
+ return -1;
+ }
+
+ json subscribeJson = json::parse(json_object_to_json_string(eventJ));
+ if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerSubscribe: No events array found in subscribe json");
+ return -1;
+ }
+ list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>());
+
+ // SUbscribe this client for the navigation events.
+ auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request);
+ for (auto event : events) {
+ if (!sCapabilityMessagingService->subscribe(*request, playbackcontrollerCapability, event)) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerSubscribe: Failed to subscribe to event: " + event);
+ return -1;
+ }
+ }
+
+ AFB_ReqSuccess(
+ source->request, json_object_new_string("Subscription to playbackcontroller events successfully completed."), NULL);
+ return 0;
+}
+
+CTLP_CAPI(playbackControllerPublish, source, argsJ, eventJ) {
+ if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) {
+ return -1;
+ }
+
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> playbackcontrollerCapability = sCapabilitiesFactory->getPlaybackController();
+ if (!playbackcontrollerCapability) {
+ sLogger->log(Level::WARNING, TAG, "playbackControllerPublish: Failed to fetch playbackcontroller capability object.");
+ return -1;
+ }
+
+ if (eventJ == nullptr) {
+ sLogger->log(Level::WARNING, TAG, "playbackControllerPublish: No arguments supplied.");
+ return -1;
+ }
+
+ json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str());
+ if (actionJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: No action found in publish json");
+ return -1;
+ }
+
+ std::string action = std::string(json_object_get_string(actionJ));
+ if (action.empty()) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: Invalid action input found in publish json");
+ return -1;
+ }
+
+ json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str());
+ if (payloadJ == nullptr) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: No playload found in publish json");
+ return -1;
+ }
+
+ if (!sCapabilityMessagingService->publish(playbackcontrollerCapability, action, payloadJ)) {
+ sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: Failed to publish message: " + action);
+ return -1;
+ }
+
+ AFB_ReqSuccess(source->request, json_object_new_string("Successfully published playbackcontroller messages."), NULL);
+ return 0;
+} \ No newline at end of file
diff --git a/src/plugins/VshlCapabilitiesApi.h b/src/plugins/VshlCapabilitiesApi.h
new file mode 100644
index 0000000..1ef1d71
--- /dev/null
+++ b/src/plugins/VshlCapabilitiesApi.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_API_INCLUDE
+#define VSHL_CAPABILITIES_API_INCLUDE
+
+#include "ctl-plugin.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CTLP_ONLOAD(plugin, ret);
+CTLP_INIT(plugin, ret);
+int guiMetadataSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int guiMetadataPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int phonecontrolSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int phonecontrolPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int navigationSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int navigationPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int playbackControllerSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+int playbackControllerPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // VSHL_CAPABILITIES_API_INCLUDE
diff --git a/src/plugins/afb/AFBApiImpl.cpp b/src/plugins/afb/AFBApiImpl.cpp
new file mode 100644
index 0000000..443a412
--- /dev/null
+++ b/src/plugins/afb/AFBApiImpl.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "afb/AFBApiImpl.h"
+
+#include "afb/include/AFBEventImpl.h"
+#include "utilities/logging/Logger.h"
+
+extern "C" {
+#define AFB_BINDING_VERSION 3
+
+#include "afb-definitions.h"
+}
+
+static std::string TAG = "vshlcapabilities::afb::AFBApiImpl";
+
+/**
+ * Specifies the severity level of a log message
+ */
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+using namespace vshlcapabilities::common::interfaces;
+using namespace vshlcapabilities::utilities::logging;
+
+namespace vshlcapabilities {
+namespace afb {
+
+std::unique_ptr<AFBApiImpl> AFBApiImpl::create(AFB_ApiT api) {
+ return std::unique_ptr<AFBApiImpl>(new AFBApiImpl(api));
+}
+
+AFBApiImpl::AFBApiImpl(AFB_ApiT api) : mApi(api), mLogger(Logger::create(api)) {
+}
+
+AFBApiImpl::~AFBApiImpl() {
+}
+
+std::shared_ptr<IAFBApi::IAFBEvent> AFBApiImpl::createEvent(const std::string& eventName) {
+ return AFBEventImpl::create(mLogger, mApi, eventName);
+}
+
+int AFBApiImpl::callSync(
+ const std::string& api,
+ const std::string& verb,
+ struct json_object* request,
+ struct json_object** result,
+ std::string& error,
+ std::string& info) {
+ char* errorStr = NULL;
+ char* infoStr = NULL;
+ int rc = AFB_ApiSync(mApi, api.c_str(), verb.c_str(), request, result, &errorStr, &infoStr);
+
+ if (errorStr) {
+ error = errorStr;
+ free(errorStr);
+ }
+
+ if (infoStr) {
+ info = infoStr;
+ free(infoStr);
+ }
+
+ return rc;
+}
+
+} // namespace afb
+} // namespace vshl
diff --git a/src/plugins/afb/AFBApiImpl.h b/src/plugins/afb/AFBApiImpl.h
new file mode 100644
index 0000000..a8d8e08
--- /dev/null
+++ b/src/plugins/afb/AFBApiImpl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_AFB_AFBAPIIMPL_H_
+#define VSHL_AFB_AFBAPIIMPL_H_
+
+#include <memory>
+
+extern "C" {
+#include "ctl-plugin.h"
+}
+
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace afb {
+
+class AFBApiImpl : public vshlcapabilities::common::interfaces::IAFBApi {
+public:
+ static std::unique_ptr<AFBApiImpl> create(AFB_ApiT api);
+
+ ~AFBApiImpl();
+
+ std::shared_ptr<IAFBEvent> createEvent(const std::string& eventName) override;
+
+ int callSync(
+ const std::string& api,
+ const std::string& verb,
+ struct json_object* request,
+ struct json_object** result,
+ std::string& error,
+ std::string& info) override;
+
+private:
+ AFBApiImpl(AFB_ApiT api);
+
+ // AFB API Binding
+ AFB_ApiT mApi;
+
+ // Logger
+ std::shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace afb
+} // namespace vshl
+
+#endif // VSHL_AFB_AFBAPIIMPL_H_
diff --git a/src/plugins/afb/AFBRequestImpl.cpp b/src/plugins/afb/AFBRequestImpl.cpp
new file mode 100644
index 0000000..3e20172
--- /dev/null
+++ b/src/plugins/afb/AFBRequestImpl.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "afb/AFBRequestImpl.h"
+
+extern "C" {
+#include "afb-definitions.h"
+}
+
+namespace vshlcapabilities {
+namespace afb {
+
+std::unique_ptr<AFBRequestImpl> AFBRequestImpl::create(AFB_ReqT afbRequest) {
+ return std::unique_ptr<AFBRequestImpl>(new AFBRequestImpl(afbRequest));
+}
+
+AFBRequestImpl::AFBRequestImpl(AFB_ReqT afbRequest) : mAfbRequest(afbRequest) {
+}
+
+void* AFBRequestImpl::getNativeRequest() {
+ return mAfbRequest;
+}
+
+} // namespace afb
+} // namespace vshl
diff --git a/src/plugins/afb/AFBRequestImpl.h b/src/plugins/afb/AFBRequestImpl.h
new file mode 100644
index 0000000..c155f31
--- /dev/null
+++ b/src/plugins/afb/AFBRequestImpl.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_AFB_AFBREQUESTIMPL_H_
+#define VSHL_AFB_AFBREQUESTIMPL_H_
+
+#include <memory>
+
+extern "C" {
+#include "ctl-plugin.h"
+}
+
+#include "interfaces/afb/IAFBApi.h"
+
+namespace vshlcapabilities {
+namespace afb {
+
+/**
+ * AFB Request impl
+ */
+class AFBRequestImpl : public vshlcapabilities::common::interfaces::IAFBRequest {
+public:
+ static std::unique_ptr<AFBRequestImpl> create(AFB_ReqT afbRequest);
+
+ // {@c IAFBRequest Implementation
+ void *getNativeRequest() override;
+ // @c IAFBRequest Implementation }
+
+private:
+ AFBRequestImpl(AFB_ReqT afbRequest);
+
+ AFB_ReqT mAfbRequest;
+};
+
+} // namespace afb
+} // namespace vshl
+
+#endif // VSHL_AFB_AFBREQUESTIMPL_H_
diff --git a/src/plugins/afb/include/AFBEventImpl.h b/src/plugins/afb/include/AFBEventImpl.h
new file mode 100644
index 0000000..2dda513
--- /dev/null
+++ b/src/plugins/afb/include/AFBEventImpl.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_AFB_EVENT_H_
+#define VSHL_AFB_EVENT_H_
+
+#include <memory>
+#include <string>
+
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+extern "C" {
+#include "ctl-plugin.h"
+#include <json-c/json.h>
+}
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace afb {
+/*
+ * This class encapsulates AFB Event.
+ */
+class AFBEventImpl : public vshlcapabilities::common::interfaces::IAFBApi::IAFBEvent {
+public:
+ static unique_ptr<AFBEventImpl>
+ create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, AFB_ApiT api,
+ const string &eventName);
+
+ // Destructor
+ ~AFBEventImpl();
+
+ /// { @c IAFBEvent implementation
+ string getName() const override;
+ bool isValid() override;
+ int publishEvent(struct json_object *payload) override;
+ bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request) override;
+ bool unsubscribe(vshlcapabilities::common::interfaces::IAFBRequest &request) override;
+ /// @c IAFBEvent implementation }
+
+private:
+ AFBEventImpl(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ AFB_ApiT api, const string &eventName);
+
+ // Make the event. This is a lazy make that happens
+ // usually during the subscribe stage.
+ void makeEventIfNeccessary();
+
+ // Binding API reference
+ AFB_ApiT mAfbApi;
+
+ // AFB Event
+ afb_event_t mAfbEvent;
+
+ // Event Name
+ string mEventName;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace afb
+} // namespace vshl
+
+#endif // VSHL_AFB_EVENT_H_
diff --git a/src/plugins/afb/src/AFBEventImpl.cpp b/src/plugins/afb/src/AFBEventImpl.cpp
new file mode 100644
index 0000000..7ddac36
--- /dev/null
+++ b/src/plugins/afb/src/AFBEventImpl.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "afb/include/AFBEventImpl.h"
+
+static string TAG = "vshlcapabilities::afb::Event";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+using namespace vshlcapabilities::common::interfaces;
+
+namespace vshlcapabilities {
+namespace afb {
+
+unique_ptr<AFBEventImpl> AFBEventImpl::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ AFB_ApiT api,
+ const string& eventName) {
+ return unique_ptr<AFBEventImpl>(new AFBEventImpl(logger, api, eventName));
+}
+
+AFBEventImpl::AFBEventImpl(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ AFB_ApiT api,
+ const string& eventName) :
+ mLogger(logger),
+ mAfbApi(api),
+ mEventName(eventName),
+ mAfbEvent(nullptr) {
+}
+
+AFBEventImpl::~AFBEventImpl() {
+}
+
+string AFBEventImpl::getName() const {
+ return mEventName;
+}
+
+bool AFBEventImpl::isValid() {
+ makeEventIfNeccessary();
+ return afb_event_is_valid(mAfbEvent) == 1 ? true : false;
+}
+
+bool AFBEventImpl::subscribe(IAFBRequest& requestInterface) {
+ makeEventIfNeccessary();
+ auto request = static_cast<AFB_ReqT>(requestInterface.getNativeRequest());
+ if (isValid() && afb_req_subscribe(request, mAfbEvent) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+bool AFBEventImpl::unsubscribe(IAFBRequest& requestInterface) {
+ makeEventIfNeccessary();
+ auto request = static_cast<AFB_ReqT>(requestInterface.getNativeRequest());
+ if (isValid() && afb_req_unsubscribe(request, mAfbEvent) == 0) {
+ return true;
+ }
+
+ return false;
+}
+
+int AFBEventImpl::publishEvent(struct json_object* payload) {
+ makeEventIfNeccessary();
+ return afb_event_push(mAfbEvent, payload);
+}
+
+void AFBEventImpl::makeEventIfNeccessary() {
+ if (mAfbEvent) {
+ return;
+ }
+
+ mLogger->log(Level::NOTICE, TAG, "Creating VSHL event: " + mEventName);
+ mAfbEvent = afb_api_make_event(mAfbApi, mEventName.c_str());
+}
+
+} // namespace afb
+} // namespace vshl
diff --git a/src/plugins/agreement.sh b/src/plugins/agreement.sh
new file mode 100755
index 0000000..2a8eb71
--- /dev/null
+++ b/src/plugins/agreement.sh
@@ -0,0 +1,43 @@
+#********************************************************************************
+# Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file 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.
+#*********************************************************************************
+
+agreement_check() {
+ cat << EOF
+
+*******************************************************************************
+The scripts provided herein will retrieve several third-party libraries,
+environments, and/or other software packages at build-time
+("External Dependencies") from third-party sources. These are terms and
+conditions that you need to agree to abide by if you choose to build the
+External Dependencies. Licenses for the External Dependencies may be found at
+README.md. If you do not agree with every term and condition
+associated with the External Dependencies, enter “QUIT” in the command line
+when prompted by the script.
+*******************************************************************************
+
+EOF
+
+ answer="dummy"
+ while [ ! -z $answer ]; do
+ read -p "Type \"QUIT\" to exit the script now, press ENTER to continue: " -r answer
+ if [ "$answer" = "QUIT" ]; then
+ exit 1
+ fi
+ echo ""
+ done
+}
+
+agreement_check
+exit 0 \ No newline at end of file
diff --git a/src/plugins/capabilities/CapabilitiesFactory.cpp b/src/plugins/capabilities/CapabilitiesFactory.cpp
new file mode 100644
index 0000000..7a65842
--- /dev/null
+++ b/src/plugins/capabilities/CapabilitiesFactory.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/CapabilitiesFactory.h"
+
+#include "capabilities/communication/include/PhoneControlCapability.h"
+#include "capabilities/guimetadata/include/GuiMetadataCapability.h"
+#include "capabilities/navigation/include/NavigationCapability.h"
+#include "capabilities/playbackcontroller/include/PlaybackControllerCapability.h"
+
+static string TAG = "vshlcapabilities::core::CapabilitiesFactory";
+
+namespace vshlcapabilities {
+namespace capabilities {
+
+// Create CapabilitiesFactory
+std::unique_ptr<CapabilitiesFactory> CapabilitiesFactory::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ auto capabilitiesFactory = std::unique_ptr<CapabilitiesFactory>(new CapabilitiesFactory(logger));
+ return capabilitiesFactory;
+}
+
+CapabilitiesFactory::CapabilitiesFactory(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ mLogger = logger;
+}
+
+std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getGuiMetadata() {
+ if (!mGuiMetadata) {
+ mGuiMetadata = vshlcapabilities::capabilities::guimetadata::GuiMetadata::create(mLogger);
+ }
+ return mGuiMetadata;
+}
+
+std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getPhoneControl() {
+ if (!mPhoneControl) {
+ mPhoneControl = vshlcapabilities::capabilities::phonecontrol::PhoneControl::create(mLogger);
+ }
+ return mPhoneControl;
+}
+
+std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getNavigation(
+ ) {
+ if (!mNavigation) {
+ mNavigation = vshlcapabilities::capabilities::navigation::Navigation::create(mLogger);
+ }
+ return mNavigation;
+}
+
+std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getPlaybackController(
+ ) {
+ if (!mPlaybackController) {
+ mPlaybackController = vshlcapabilities::capabilities::playbackcontroller::PlaybackController::create(mLogger);
+ }
+ return mPlaybackController;
+}
+
+} // namespace capabilities
+} // namespace vshl \ No newline at end of file
diff --git a/src/plugins/capabilities/CapabilitiesFactory.h b/src/plugins/capabilities/CapabilitiesFactory.h
new file mode 100644
index 0000000..b97fcfe
--- /dev/null
+++ b/src/plugins/capabilities/CapabilitiesFactory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_
+#define VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_
+
+#include <memory>
+
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+/*
+ * Factory for creating different capability objects.
+ */
+class CapabilitiesFactory {
+public:
+ // Create CapabilitiesFactory
+ static std::unique_ptr<CapabilitiesFactory> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ // GUI Metadata capability
+ std::shared_ptr<common::interfaces::ICapability> getGuiMetadata();
+
+ // Phone call control capability
+ std::shared_ptr<common::interfaces::ICapability> getPhoneControl();
+
+ // Navigation capability
+ std::shared_ptr<common::interfaces::ICapability> getNavigation();
+
+ // PLaybackcontroller capability
+ std::shared_ptr<common::interfaces::ICapability> getPlaybackController();
+
+ // Destructor
+ ~CapabilitiesFactory() = default;
+
+private:
+ // Constructor
+ CapabilitiesFactory(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ // Capabilities
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mGuiMetadata;
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mPhoneControl;
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mNavigation;
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mPlaybackController;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_
diff --git a/src/plugins/capabilities/CapabilityMessagingService.cpp b/src/plugins/capabilities/CapabilityMessagingService.cpp
new file mode 100644
index 0000000..8dd6e26
--- /dev/null
+++ b/src/plugins/capabilities/CapabilityMessagingService.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/CapabilityMessagingService.h"
+
+#include "capabilities/core/include/PublisherForwarder.h"
+#include "capabilities/core/include/SubscriberForwarder.h"
+
+static string TAG = "vshlcapabilities::capabilities::CapabilityMessagingService";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+
+// Create a CapabilityMessagingService.
+unique_ptr<CapabilityMessagingService> CapabilityMessagingService::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi) {
+ if (logger == nullptr) {
+ return nullptr;
+ }
+
+ if (afbApi == nullptr) {
+ logger->log(Level::ERROR, TAG, "Failed to create CapabilityMessagingService: AFB API null");
+ return nullptr;
+ }
+
+ auto capabilityMessageService =
+ std::unique_ptr<CapabilityMessagingService>(new CapabilityMessagingService(logger, afbApi));
+ return capabilityMessageService;
+}
+
+CapabilityMessagingService::~CapabilityMessagingService() {
+ mMessageChannelsMap.clear();
+}
+
+CapabilityMessagingService::CapabilityMessagingService(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi) :
+ mAfbApi(afbApi),
+ mLogger(logger) {
+}
+
+// Subscribe to capability specific messages.
+bool CapabilityMessagingService::subscribe(
+ vshlcapabilities::common::interfaces::IAFBRequest& request,
+ shared_ptr<common::interfaces::ICapability> capability,
+ const string action) {
+ auto capabilityName = capability->getName();
+
+ if (capabilityName.empty()) {
+ mLogger->log(Level::ERROR, TAG, "Failed to subscribe to message. Invalid input.");
+ return false;
+ }
+
+ auto messageChannel = getMessageChannel(capability);
+ return messageChannel->subscribe(request, action);
+}
+
+// Publish capability messages.
+bool CapabilityMessagingService::publish(
+ shared_ptr<common::interfaces::ICapability> capability,
+ const string action,
+ json_object* payload) {
+ auto capabilityName = capability->getName();
+
+ if (capabilityName.empty()) {
+ mLogger->log(Level::ERROR, TAG, "Failed to publish message. Invalid input.");
+ return false;
+ }
+
+ auto messageChannelIt = mMessageChannelsMap.find(capabilityName);
+ if (messageChannelIt == mMessageChannelsMap.end()) {
+ mLogger->log(
+ Level::ERROR,
+ TAG,
+ "No one subscribed for a message of capability. " + capabilityName);
+ return false;
+ }
+
+ return messageChannelIt->second->publish(action, payload);
+}
+
+shared_ptr<vshlcapabilities::capabilities::core::MessageChannel> CapabilityMessagingService::getMessageChannel(
+ shared_ptr<common::interfaces::ICapability> capability) {
+ auto capabilityName = capability->getName();
+
+ if (capabilityName.empty()) {
+ mLogger->log(Level::ERROR, TAG, "Failed to create message channel. Invalid input.");
+ return nullptr;
+ }
+
+ auto messageChannelIt = mMessageChannelsMap.find(capabilityName);
+ if (messageChannelIt == mMessageChannelsMap.end()) {
+ mLogger->log(Level::INFO, TAG, "Creating new message channel for capability: " + capabilityName);
+ auto messageChannel = vshlcapabilities::capabilities::core::MessageChannel::create(mLogger, mAfbApi, capability);
+ mMessageChannelsMap.insert(make_pair(capabilityName, messageChannel));
+ return messageChannel;
+ }
+
+ return messageChannelIt->second;
+}
+
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/CapabilityMessagingService.h b/src/plugins/capabilities/CapabilityMessagingService.h
new file mode 100644
index 0000000..79edfa8
--- /dev/null
+++ b/src/plugins/capabilities/CapabilityMessagingService.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_
+#define VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "capabilities/core/include/MessageChannel.h"
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+/*
+ * This hosts service APIs that clients can use to subscribe and
+ * forward capability messages. Each capability has a name and
+ * direction (upstream/downstream). Upstream messages are from
+ * voiceagents to Apps and downstream messages are Apps to voiceagents.
+ * This class will use a factory to create publisher and subcribers for
+ * each capability and create assiociations between them.
+ */
+class CapabilityMessagingService {
+public:
+ // Create a CapabilityMessagingService.
+ static std::unique_ptr<CapabilityMessagingService>
+ create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi);
+
+ // Subscribe to capability specific messages.
+ bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request,
+ shared_ptr<common::interfaces::ICapability> capability,
+ const string action);
+
+ // Publish capability messages.
+ bool publish(shared_ptr<common::interfaces::ICapability> capability,
+ const string action, json_object* payload);
+
+ // Destructor
+ ~CapabilityMessagingService();
+
+private:
+ // Constructor
+ CapabilityMessagingService(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi);
+
+ // Binding API reference
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> mAfbApi;
+
+ // Create a message channel for the capability.
+ shared_ptr<vshlcapabilities::capabilities::core::MessageChannel>
+ getMessageChannel(shared_ptr<common::interfaces::ICapability> capability);
+
+ // Map of capabilities to message channels.
+ unordered_map<string, shared_ptr<vshlcapabilities::capabilities::core::MessageChannel>>
+ mMessageChannelsMap;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_
diff --git a/src/plugins/capabilities/communication/include/PhoneControlCapability.h b/src/plugins/capabilities/communication/include/PhoneControlCapability.h
new file mode 100644
index 0000000..87dc339
--- /dev/null
+++ b/src/plugins/capabilities/communication/include/PhoneControlCapability.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_
+#define VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_
+
+#include <memory>
+
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace phonecontrol {
+
+/*
+ * PhoneControl capability. Calls are initiated in the endpoint.
+ */
+class PhoneControl : public common::interfaces::ICapability {
+public:
+ // Create a PhoneControl.
+ static std::shared_ptr<PhoneControl> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ ~PhoneControl() = default;
+
+protected:
+ string getName() const override;
+
+ list<string> getUpstreamMessages() const override;
+
+ list<string> getDownstreamMessages() const override;
+
+private:
+ PhoneControl(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace phonecontrol
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_
diff --git a/src/plugins/capabilities/communication/include/PhoneControlMessages.h b/src/plugins/capabilities/communication/include/PhoneControlMessages.h
new file mode 100644
index 0000000..23d2fae
--- /dev/null
+++ b/src/plugins/capabilities/communication/include/PhoneControlMessages.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_
+#define VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace phonecontrol {
+
+static string NAME = "phonecontrol";
+
+/*
+ ******************************************************************************************************
+ * Supported actions from VA -> APPS
+ ******************************************************************************************************
+ */
+
+/* Dial message sent from VA to app handling the calling.
+ *
+ * payload:
+ * {
+ * "callId": "{{STRING}}",
+ * "callee": {
+ * "details": "{{STRING}}",
+ * "defaultAddress": {
+ * "protocol": "{{STRING}}",
+ * "format": "{{STRING}}",
+ * "value": "{{STRING}}"
+ * },
+ * "alternativeAddresses": [{
+ * "protocol": "{{STRING}}",
+ * "format": "{{STRING}}",
+ * "value": {{STRING}}
+ * }]
+ * }
+ * }
+ * }
+ *
+ * callId (required): A unique identifier for the call
+ * callee (required): The destination of the outgoing call
+ * callee.details (optional): Descriptive information about the callee
+ * callee.defaultAddress (required): The default address to use for calling the callee
+ * callee.alternativeAddresses (optional): An array of alternate addresses for the existing callee
+ * address.protocol (required): The protocol for this address of the callee (e.g. PSTN, SIP, H323, etc.)
+ * address.format (optional): The format for this address of the callee (e.g. E.164, E.163, E.123, DIN5008, etc.)
+ * address.value (required): The address of the callee.
+ *
+ */
+static string PHONECONTROL_DIAL = "dial";
+/**
+ * Notifies the platform implementation to redial the last called phone number.
+ *
+ * After returning @c true, if no stored number is available to be redialed, @c PhoneCallController::callFailed with
+ * @c CallError::NO_NUMBER_FOR_REDIAL should be called.
+ *
+ * @param [in] payload Details of the redial request in structured JSON format. See the following
+ * payload:
+ * {
+ * "callId": "{{STRING}}"
+ * }
+ * @li callId (required): A unique identifier for the call
+ *
+ * @return @c true if the platform implementation successfully handled the call
+ */
+static string PHONECONTROL_REDIAL = "redial";
+/**
+ * Notifies the platform implementation to answer an inbound call
+ *
+ * @param [in] payload Details of the answer request in structured JSON format. See the following
+ * payload:
+ * {
+ * "callId": "{{STRING}}",
+ * }
+ * @li callId (required): The unique identifier for the call to answer
+ */
+static string PHONECONTROL_ANSWER = "answer";
+/**
+ * Notifies the platform implementation to end an ongoing call or stop inbound or outbound call setup
+ *
+ * @param [in] payload Details of the stop request in structured JSON format. See the following
+ * payload:
+ * {
+ * "callId": "{{STRING}}"
+ * }
+ * @li callId (required): The unique identifier for the call to be stopped
+ */
+static string PHONECONTROL_STOP = "stop";
+/**
+ * Notifies the platform implementation to send a DTMF signal to the calling device
+ *
+ * @param [in] payload Details of the DTMF request in structured JSON format. See the following
+ * payload:
+ * {
+ * "callId": "{{STRING}}",
+ * "signal": "{{STRING}}"
+ * }
+ * @li callId (required): The unique identifier for the call
+ * @li signal (required): The DTMF string to be sent to the calling device associated with the callId
+ */
+static string PHONECONTROL_SEND_DTMF = "send_dtmf";
+
+/*
+ ******************************************************************************************************
+ * Supported actions from Apps -> VA
+ ******************************************************************************************************
+ */
+
+/*
+ * App notifies the voiceagents of a change in connection state of a calling device.
+ *
+ * payload:
+ * {
+ * "state" : "{{STRING}}" // CONNECTED or DISCONNECTED
+ * }
+ */
+static string PHONECONTROL_CONNECTIONSTATE_CHANGED = "connection_state_changed";
+/*
+ * App notifies the voiceagents that call is activated
+ *
+ * callId must match the one that is sent by VA with DIAL message above.
+ *
+ * payload:
+ * {
+ * "callId" : "{{STRING}}"
+ * "state" : "{{STRING}}" // IDLE, ACTIVE, TRYING, INBOUND_RINGING, OUTBOUND_RINGING, INVITED
+ * }
+ */
+static string PHONECONTROL_CALL_STATE_CHANGED = "call_state_changed";
+/*
+ * App notifies the voiceagents of an error in initiating or maintaining a
+ * call on a calling device
+ *
+ * callId must match the one that is sent by VA with DIAL message above.
+ * error: below status codes.
+ * 4xx: Validation failure for the input from the DIAL message
+ * 500: Internal error on the platform unrelated to the cellular network
+ * 503: Error on the platform related to the cellular network
+ *
+ * payload :
+ * {
+ * "callId" : "{{STRING}}"
+ * "error" : "{{STRING}}"
+ * }
+ */
+static string PHONECONTROL_CALL_FAILED = "call_failed";
+/**
+ * App notifies the voiceagents that a caller id was received for an inbound call
+ * payload :
+ * {
+ * "callId" : "{{STRING}}"
+ * "callerId" : "{{STRING}}"
+ * }
+ *
+ * @param [in] callId The unique identifier for the call associated with the callId
+ * @param [in] callerId The caller's identifier or phone number
+ */
+static string PHONECONTROL_CALLERID_RECEIVED = "caller_id_received";
+
+/**
+ * Notifies the Engine that sending the DTMF signal succeeded.
+ * payload :
+ * {
+ * "callId" : "{{STRING}}"
+ * }
+ * @param [in] callId The unique identifier for the associated call
+ *
+ * PhoneCallController::sendDTMF
+ */
+static string PHONECONTROL_SEND_DTMF_SUCCEEDED = "send_dtmf_succeeded";
+
+// List of actions that are delivered from VA -> Apps
+static list<string> PHONECONTROL_UPSTREAM_ACTIONS = {
+ PHONECONTROL_DIAL,
+ PHONECONTROL_REDIAL,
+ PHONECONTROL_ANSWER,
+ PHONECONTROL_STOP,
+ PHONECONTROL_SEND_DTMF
+};
+
+// List of actions that are delivered from Apps -> VA
+static list<string> PHONECONTROL_DOWNSTREAM_ACTIONS = {PHONECONTROL_CONNECTIONSTATE_CHANGED,
+ PHONECONTROL_CALL_STATE_CHANGED,
+ PHONECONTROL_CALL_FAILED,
+ PHONECONTROL_CALLERID_RECEIVED,
+ PHONECONTROL_SEND_DTMF_SUCCEEDED};
+
+} // namespace phonecontrol
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_
diff --git a/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp b/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp
new file mode 100644
index 0000000..75296bf
--- /dev/null
+++ b/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/communication/include/PhoneControlCapability.h"
+#include "capabilities/communication/include/PhoneControlMessages.h"
+
+const string TAG = "vshlcapabilities::capabilities::phonecontrol";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace phonecontrol {
+
+// Create a phonecontrol.
+shared_ptr<PhoneControl> PhoneControl::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ auto phonecontrol = std::shared_ptr<PhoneControl>(new PhoneControl(logger));
+ return phonecontrol;
+}
+
+PhoneControl::PhoneControl(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ mLogger = logger;
+}
+
+string PhoneControl::getName() const {
+ return NAME;
+}
+
+list<string> PhoneControl::getUpstreamMessages() const {
+ return PHONECONTROL_UPSTREAM_ACTIONS;
+}
+
+list<string> PhoneControl::getDownstreamMessages() const {
+ return PHONECONTROL_DOWNSTREAM_ACTIONS;
+}
+
+} // namespace phonecontrol
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/core/include/MessageChannel.h b/src/plugins/capabilities/core/include/MessageChannel.h
new file mode 100644
index 0000000..79e4eab
--- /dev/null
+++ b/src/plugins/capabilities/core/include/MessageChannel.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_
+#define VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_
+
+#include <memory>
+
+#include "capabilities/core/include/PublisherForwarder.h"
+#include "capabilities/core/include/SubscriberForwarder.h"
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+/*
+ * MessageChannel has one end as publisher forwarder and the other end
+ * as subscriber forwarder.
+ */
+class MessageChannel {
+public:
+ // Create a MessageChannel.
+ static std::shared_ptr<MessageChannel>
+ create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Sends the message
+ bool publish(const string action, json_object* payload);
+
+ // Subscribe
+ bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request,
+ const string action);
+
+ // Destructor
+ virtual ~MessageChannel() = default;
+
+private:
+ // Constructor
+ MessageChannel(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Forwarders
+ shared_ptr<PublisherForwarder> mPublisherForwarder;
+ shared_ptr<SubscriberForwarder> mSubscriberForwarder;
+};
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_
diff --git a/src/plugins/capabilities/core/include/PublisherForwarder.h b/src/plugins/capabilities/core/include/PublisherForwarder.h
new file mode 100644
index 0000000..01e9523
--- /dev/null
+++ b/src/plugins/capabilities/core/include/PublisherForwarder.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_
+#define VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_
+
+#include <memory>
+
+#include "capabilities/core/include/SubscriberForwarder.h"
+
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+/*
+ * This class is responsible for forwarding the messages to be published
+ * to subscriber forwarder. Subscriber forwarder will deliver the messages
+ * as AFB Events to all the subscribed clients.
+ * There is one PublisherForwarder and one SubscriberForwarder per capability.
+ */
+class PublisherForwarder {
+public:
+ // Create a PublisherForwarder.
+ static std::shared_ptr<PublisherForwarder> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Connect a subscriber forwarder to this publisher forwarder
+ void setSubscriberForwarder(shared_ptr<SubscriberForwarder> subscriberForwarder);
+
+ // Forward message to the subscriber forwarder
+ bool forwardMessage(const string action, json_object* payload);
+
+ // Destructor
+ ~PublisherForwarder();
+
+private:
+ // Constructor
+ PublisherForwarder(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Subscriber forwarder connected to this publisher forwarder.
+ shared_ptr<SubscriberForwarder> mSubscriberForwarder;
+
+ // Capability
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mCapability;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_
diff --git a/src/plugins/capabilities/core/include/SubscriberForwarder.h b/src/plugins/capabilities/core/include/SubscriberForwarder.h
new file mode 100644
index 0000000..ac469b3
--- /dev/null
+++ b/src/plugins/capabilities/core/include/SubscriberForwarder.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_
+#define VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "interfaces/afb/IAFBApi.h"
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+/*
+ * This class is responsible for forwarding the messages publishing
+ * to the actual clients using AFB.
+ */
+class SubscriberForwarder {
+public:
+ // Create a SubscriberForwarder.
+ static std::shared_ptr<SubscriberForwarder>
+ create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Publish a capability message to the actual client.
+ bool forwardMessage(const string action, json_object* payload);
+
+ // Subscribe
+ bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request,
+ const string action);
+
+ // Destructor
+ ~SubscriberForwarder();
+
+private:
+ // Constructor
+ SubscriberForwarder(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability);
+
+ // Creates both upstream and downstream events
+ void createEvents();
+
+ // Binding API reference
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> mAfbApi;
+
+ // Capability
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> mCapability;
+
+ // Maps of capability action events to its corresponding Event object.
+ // Event name maps to Action Name
+ unordered_map<string, shared_ptr<common::interfaces::IAFBApi::IAFBEvent>>
+ mUpstreamEventsMap;
+ unordered_map<string, shared_ptr<common::interfaces::IAFBApi::IAFBEvent>>
+ mDownstreamEventsMap;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_
diff --git a/src/plugins/capabilities/core/src/MessageChannel.cpp b/src/plugins/capabilities/core/src/MessageChannel.cpp
new file mode 100644
index 0000000..f4e55dd
--- /dev/null
+++ b/src/plugins/capabilities/core/src/MessageChannel.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/core/include/MessageChannel.h"
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+
+// Create a MessageChannel.
+std::shared_ptr<MessageChannel> MessageChannel::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> api,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) {
+ auto messageChannel = std::shared_ptr<MessageChannel>(new MessageChannel(logger, api, capability));
+ return messageChannel;
+}
+
+MessageChannel::MessageChannel(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> api,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) {
+ // Subscriber forwarder
+ mSubscriberForwarder = SubscriberForwarder::create(logger, api, capability);
+ // Publisher forwarder
+ mPublisherForwarder = PublisherForwarder::create(logger, capability);
+ mPublisherForwarder->setSubscriberForwarder(mSubscriberForwarder);
+}
+
+bool MessageChannel::publish(const string action, json_object* payload) {
+ return mPublisherForwarder->forwardMessage(action, payload);
+}
+
+bool MessageChannel::subscribe(vshlcapabilities::common::interfaces::IAFBRequest& request, const string action) {
+ return mSubscriberForwarder->subscribe(request, action);
+}
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/core/src/PublisherForwarder.cpp b/src/plugins/capabilities/core/src/PublisherForwarder.cpp
new file mode 100644
index 0000000..8f8f542
--- /dev/null
+++ b/src/plugins/capabilities/core/src/PublisherForwarder.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/core/include/PublisherForwarder.h"
+
+static string TAG = "vshlcapabilities::capabilities::PublisherForwarder";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+
+// Create a PublisherForwarder.
+std::shared_ptr<PublisherForwarder> PublisherForwarder::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) {
+ if (logger == nullptr) {
+ return nullptr;
+ }
+
+ if (capability == nullptr) {
+ logger->log(Level::ERROR, TAG, "Failed to create PublisherForwarder: Capability null");
+ return nullptr;
+ }
+
+ auto publisherForwarder = std::shared_ptr<PublisherForwarder>(new PublisherForwarder(logger, capability));
+ return publisherForwarder;
+}
+
+// Constructor
+PublisherForwarder::PublisherForwarder(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) {
+ mCapability = capability;
+ mLogger = logger;
+}
+
+// Destructor
+PublisherForwarder::~PublisherForwarder() {
+}
+
+void PublisherForwarder::setSubscriberForwarder(shared_ptr<SubscriberForwarder> subscriberForwarder) {
+ mSubscriberForwarder = subscriberForwarder;
+}
+
+bool PublisherForwarder::forwardMessage(const string action, json_object* payload) {
+ if (!mSubscriberForwarder) {
+ mLogger->log(Level::ERROR, TAG, "Failed to forward message for capability: " + mCapability->getName());
+ return false;
+ }
+
+ return mSubscriberForwarder->forwardMessage(action, payload);
+}
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/core/src/SubscriberForwarder.cpp b/src/plugins/capabilities/core/src/SubscriberForwarder.cpp
new file mode 100644
index 0000000..970dbf0
--- /dev/null
+++ b/src/plugins/capabilities/core/src/SubscriberForwarder.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/core/include/SubscriberForwarder.h"
+
+static string TAG = "vshlcapabilities::capabilities::SubscriberForwarder";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace core {
+
+// Create a SubscriberForwarder.
+std::shared_ptr<SubscriberForwarder> SubscriberForwarder::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) {
+ if (logger == nullptr) {
+ return nullptr;
+ }
+
+ if (afbApi == nullptr) {
+ logger->log(Level::ERROR, TAG, "Failed to create SubscriberForwarder: AFB API null");
+ return nullptr;
+ }
+
+ if (capability == nullptr) {
+ logger->log(Level::ERROR, TAG, "Failed to create SubscriberForwarder: Capability null");
+ return nullptr;
+ }
+
+ auto subscriberForwarder =
+ std::shared_ptr<SubscriberForwarder>(new SubscriberForwarder(logger, afbApi, capability));
+ return subscriberForwarder;
+}
+
+SubscriberForwarder::SubscriberForwarder(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger,
+ shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi,
+ shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) :
+ mAfbApi(afbApi),
+ mLogger(logger),
+ mCapability(capability) {
+ createEvents();
+}
+
+SubscriberForwarder::~SubscriberForwarder() {
+ mUpstreamEventsMap.clear();
+ mDownstreamEventsMap.clear();
+}
+
+void SubscriberForwarder::createEvents() {
+ if (!mCapability) {
+ mLogger->log(Level::NOTICE, TAG, "Create Events failed. No capability assigned.");
+ return;
+ }
+
+ // Upstream events
+ auto upstreamEvents = mCapability->getUpstreamMessages();
+ for (auto upstreamEventName : upstreamEvents) {
+ auto it = mUpstreamEventsMap.find(upstreamEventName);
+ if (it == mUpstreamEventsMap.end() && mAfbApi) {
+ // create a new event and add it to the map.
+ shared_ptr<common::interfaces::IAFBApi::IAFBEvent> event = mAfbApi->createEvent(upstreamEventName);
+ if (event == nullptr) {
+ mLogger->log(Level::ERROR, TAG, "Failed to create upstream event: " + upstreamEventName);
+ } else {
+ mUpstreamEventsMap.insert(make_pair(upstreamEventName, event));
+ }
+ }
+ }
+
+ // Downstream events
+ auto downstreamEvents = mCapability->getDownstreamMessages();
+ for (auto downstreamEventName : downstreamEvents) {
+ auto it = mDownstreamEventsMap.find(downstreamEventName);
+ if (it == mDownstreamEventsMap.end() && mAfbApi) {
+ // create a new event and add it to the map.
+ shared_ptr<common::interfaces::IAFBApi::IAFBEvent> event = mAfbApi->createEvent(downstreamEventName);
+ if (event == nullptr) {
+ mLogger->log(Level::ERROR, TAG, "Failed to create downstream event: " + downstreamEventName);
+ } else {
+ mDownstreamEventsMap.insert(make_pair(downstreamEventName, event));
+ }
+ }
+ }
+}
+
+bool SubscriberForwarder::forwardMessage(const string action, json_object* payload) {
+ auto upstreamEventIt = mUpstreamEventsMap.find(action);
+ if (upstreamEventIt != mUpstreamEventsMap.end()) {
+ mLogger->log(Level::NOTICE, TAG, "Publishing upstream event: " + action);
+ upstreamEventIt->second->publishEvent(payload);
+ return true;
+ }
+
+ auto downstreamEventIt = mDownstreamEventsMap.find(action);
+ if (downstreamEventIt != mDownstreamEventsMap.end()) {
+ mLogger->log(Level::NOTICE, TAG, "Publishing downstream event: " + action);
+ downstreamEventIt->second->publishEvent(payload);
+ return true;
+ }
+
+ mLogger->log(Level::NOTICE, TAG, "Failed to publish upstream event: " + action);
+ return false;
+}
+
+bool SubscriberForwarder::subscribe(vshlcapabilities::common::interfaces::IAFBRequest& request, const string action) {
+ auto upstreamEventIt = mUpstreamEventsMap.find(action);
+ if (upstreamEventIt != mUpstreamEventsMap.end()) {
+ mLogger->log(Level::NOTICE, TAG, "Subscribing to upstream event: " + action);
+ return upstreamEventIt->second->subscribe(request);
+ }
+
+ auto downstreamEventIt = mDownstreamEventsMap.find(action);
+ if (downstreamEventIt != mDownstreamEventsMap.end()) {
+ mLogger->log(Level::NOTICE, TAG, "Subscribing to downstream event: " + action);
+ return downstreamEventIt->second->subscribe(request);
+ }
+
+ mLogger->log(Level::NOTICE, TAG, "Failed to subscribe to upstream event: " + action);
+ return false;
+}
+
+} // namespace core
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h b/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h
new file mode 100644
index 0000000..ecaf09f
--- /dev/null
+++ b/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_
+#define VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_
+
+#include <memory>
+
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace guimetadata {
+
+/*
+ * GuiMetadata capability
+ */
+class GuiMetadata : public common::interfaces::ICapability {
+public:
+ // Create a GuiMetadata.
+ static std::shared_ptr<GuiMetadata> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ ~GuiMetadata() = default;
+
+protected:
+ string getName() const override;
+
+ list<string> getUpstreamMessages() const override;
+
+ list<string> getDownstreamMessages() const override;
+
+private:
+ GuiMetadata(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace guimetadata
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_
diff --git a/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h b/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h
new file mode 100644
index 0000000..07f4725
--- /dev/null
+++ b/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_
+#define VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace guimetadata {
+
+static string NAME = "guimetadata";
+
+/*
+ ******************************************************************************************************
+ * Supported actions from VA -> APPS
+ ******************************************************************************************************
+ */
+static string GUIMETADATA_RENDER_TEMPLATE = "render_template";
+static string GUIMETADATA_CLEAR_TEMPLATE = "clear_template";
+static string GUIMETADATA_RENDER_PLAYER_INFO = "render_player_info";
+static string GUIMETADATA_CLEAR_PLAYER_INFO = "clear_player_info";
+
+
+// List of actions that are delivered from VA -> Apps
+static list<string> GUIMETADATA_UPSTREAM_ACTIONS = {GUIMETADATA_RENDER_TEMPLATE,
+ GUIMETADATA_CLEAR_TEMPLATE,
+ GUIMETADATA_RENDER_PLAYER_INFO,
+ GUIMETADATA_CLEAR_PLAYER_INFO};
+
+/*
+ ******************************************************************************************************
+ * Supported actions from APPS -> VA
+ ******************************************************************************************************
+ */
+
+// List of actions that are delivered from Apps -> VA
+static list<string> GUIMETADATA_DOWNSTREAM_ACTIONS = {};
+
+} // namespace guimetadata
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_
diff --git a/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp b/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp
new file mode 100644
index 0000000..df90c91
--- /dev/null
+++ b/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/guimetadata/include/GuiMetadataCapability.h"
+#include "capabilities/guimetadata/include/GuiMetadataMessages.h"
+
+const string TAG = "vshlcapabilities::capabilities::guimetadata";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace guimetadata {
+
+// Create a GuiMetadata.
+shared_ptr<GuiMetadata> GuiMetadata::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ auto guiMetadata = std::shared_ptr<GuiMetadata>(new GuiMetadata(logger));
+ return guiMetadata;
+}
+
+GuiMetadata::GuiMetadata(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ mLogger = logger;
+}
+
+string GuiMetadata::getName() const {
+ return NAME;
+}
+
+list<string> GuiMetadata::getUpstreamMessages() const {
+ return GUIMETADATA_UPSTREAM_ACTIONS;
+}
+
+list<string> GuiMetadata::getDownstreamMessages() const {
+ return GUIMETADATA_DOWNSTREAM_ACTIONS;
+}
+
+} // namespace guimetadata
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/navigation/include/NavigationCapability.h b/src/plugins/capabilities/navigation/include/NavigationCapability.h
new file mode 100644
index 0000000..bb055a8
--- /dev/null
+++ b/src/plugins/capabilities/navigation/include/NavigationCapability.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_
+#define VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_
+
+#include <memory>
+
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace navigation {
+
+/*
+ * Navigation capability
+ */
+class Navigation : public common::interfaces::ICapability {
+public:
+ // Create a Navigation.
+ static std::shared_ptr<Navigation> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ ~Navigation() = default;
+
+protected:
+ string getName() const override;
+
+ list<string> getUpstreamMessages() const override;
+
+ list<string> getDownstreamMessages() const override;
+
+private:
+ Navigation(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace navigation
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_
diff --git a/src/plugins/capabilities/navigation/include/NavigationMessages.h b/src/plugins/capabilities/navigation/include/NavigationMessages.h
new file mode 100644
index 0000000..00c0c65
--- /dev/null
+++ b/src/plugins/capabilities/navigation/include/NavigationMessages.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_
+#define VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace navigation {
+
+static string NAME = "navigation";
+
+/*
+ ******************************************************************************************************
+ * Supported actions from VA -> APPS
+ ******************************************************************************************************
+ */
+static string NAVIGATION_SET_DESTINATION = "set_destination";
+static string NAVIGATION_CANCEL = "cancel_navigation";
+
+// Supported actions from Apps -> VA
+
+// List of actions that are delivered from VA -> Apps
+static list<string> NAVIGATION_UPSTREAM_ACTIONS = {
+ NAVIGATION_SET_DESTINATION,
+ NAVIGATION_CANCEL,
+};
+
+/*
+ ******************************************************************************************************
+ * Supported actions from APPS -> VA
+ ******************************************************************************************************
+ */
+static list<string> NAVIGATION_DOWNSTREAM_ACTIONS = {};
+
+} // namespace navigation
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_
diff --git a/src/plugins/capabilities/navigation/src/NavigationCapability.cpp b/src/plugins/capabilities/navigation/src/NavigationCapability.cpp
new file mode 100644
index 0000000..e1c6cda
--- /dev/null
+++ b/src/plugins/capabilities/navigation/src/NavigationCapability.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/navigation/include/NavigationCapability.h"
+#include "capabilities/navigation/include/NavigationMessages.h"
+
+const string TAG = "vshlcapabilities::capabilities::navigation";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace navigation {
+
+// Create a Navigation.
+shared_ptr<Navigation> Navigation::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ auto navigation = std::shared_ptr<Navigation>(new Navigation(logger));
+ return navigation;
+}
+
+Navigation::Navigation(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ mLogger = logger;
+}
+
+string Navigation::getName() const {
+ return NAME;
+}
+
+list<string> Navigation::getUpstreamMessages() const {
+ return NAVIGATION_UPSTREAM_ACTIONS;
+}
+
+list<string> Navigation::getDownstreamMessages() const {
+ return NAVIGATION_DOWNSTREAM_ACTIONS;
+}
+
+} // namespace navigation
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h
new file mode 100644
index 0000000..e80b213
--- /dev/null
+++ b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_
+#define VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_
+
+#include <memory>
+
+#include "interfaces/capabilities/ICapability.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace playbackcontroller {
+
+/*
+ * PlaybackController capability. Calls are initiated in the endpoint.
+ */
+class PlaybackController : public common::interfaces::ICapability {
+public:
+ // Create a PlaybackController.
+ static std::shared_ptr<PlaybackController> create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ ~PlaybackController() = default;
+
+protected:
+ string getName() const override;
+
+ list<string> getUpstreamMessages() const override;
+
+ list<string> getDownstreamMessages() const override;
+
+private:
+ PlaybackController(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace playbackcontroller
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_
diff --git a/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h
new file mode 100644
index 0000000..224b8dd
--- /dev/null
+++ b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_
+#define VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace playbackcontroller {
+
+static string NAME = "playbackcontroller";
+
+/*
+ ******************************************************************************************************
+ * Supported actions from APPS -> VA
+ ******************************************************************************************************
+ */
+// List of actions that are delivered from VA -> Apps
+static list<string> PLAYBACKCONTROLLER_UPSTREAM_ACTIONS = {
+
+};
+
+
+/*
+ ******************************************************************************************************
+ * Supported actions from VA -> APPS
+ ******************************************************************************************************
+ */
+// List of actions that are delivered from Apps -> VA
+/*
+ * payload :
+ * {
+ * "button" : "{{STRING}}" // play, pause, next, previous, skip-forward, skip-backward
+ * }
+ * @param [in] button Button pressed by the user.
+ *
+ */
+static string PLAYBACKCONTROLLER_BUTTONPRESSED = "button_pressed";
+
+static list<string> PLAYBACKCONTROLLER_DOWNSTREAM_ACTIONS = {
+ PLAYBACKCONTROLLER_BUTTONPRESSED
+};
+
+} // namespace playbackcontroller
+} // namespace capabilities
+} // namespace vshl
+
+#endif // VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_
diff --git a/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp b/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp
new file mode 100644
index 0000000..a5abbed
--- /dev/null
+++ b/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "capabilities/playbackcontroller/include/PlaybackControllerCapability.h"
+#include "capabilities/playbackcontroller/include/PlaybackControllerMessages.h"
+
+const string TAG = "vshlcapabilities::capabilities::playbackcontroller";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace capabilities {
+namespace playbackcontroller {
+
+// Create a playbackcontroller.
+shared_ptr<PlaybackController> PlaybackController::create(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ auto playbackcontroller = std::shared_ptr<PlaybackController>(new PlaybackController(logger));
+ return playbackcontroller;
+}
+
+PlaybackController::PlaybackController(
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ mLogger = logger;
+}
+
+string PlaybackController::getName() const {
+ return NAME;
+}
+
+list<string> PlaybackController::getUpstreamMessages() const {
+ return PLAYBACKCONTROLLER_UPSTREAM_ACTIONS;
+}
+
+list<string> PlaybackController::getDownstreamMessages() const {
+ return PLAYBACKCONTROLLER_DOWNSTREAM_ACTIONS;
+}
+
+} // namespace playbackcontroller
+} // namespace capabilities
+} // namespace vshl
diff --git a/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp b/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp
new file mode 100644
index 0000000..5d3971d
--- /dev/null
+++ b/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 <gtest/gtest.h>
+
+#include "capabilities/CapabilityMessagingService.h"
+
+#include "test/common/ConsoleLogger.h"
+#include "test/mocks/AFBApiMock.h"
+#include "test/mocks/AFBEventMock.h"
+#include "test/mocks/AFBRequestMock.h"
+#include "test/mocks/CapabilityMock.h"
+
+using namespace vshlcapabilities::common::interfaces;
+using namespace vshlcapabilities::capabilities;
+using namespace vshlcapabilities::test::common;
+
+namespace vshlcapabilities {
+namespace test {
+
+class CapabilityMessagingServiceTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mConsoleLogger = std::make_shared<ConsoleLogger>();
+ mAfbApi = std::make_shared<::testing::NiceMock<AFBApiMock>>();
+ }
+
+ std::shared_ptr<::testing::NiceMock<AFBApiMock>> mAfbApi;
+ std::shared_ptr<ConsoleLogger> mConsoleLogger;
+};
+
+TEST_F(CapabilityMessagingServiceTest, failsInitializationOnInvalidParams) {
+ auto service = CapabilityMessagingService::create(mConsoleLogger, nullptr);
+ ASSERT_EQ(service, nullptr);
+
+ service = CapabilityMessagingService::create(nullptr, mAfbApi);
+ ASSERT_EQ(service, nullptr);
+}
+
+TEST_F(CapabilityMessagingServiceTest, initializesSuccessfully) {
+ auto service = CapabilityMessagingService::create(mConsoleLogger, mAfbApi);
+ ASSERT_NE(service, nullptr);
+}
+
+TEST_F(CapabilityMessagingServiceTest, canSubscribeAndPublishCapabilityEvents) {
+ auto service = CapabilityMessagingService::create(mConsoleLogger, mAfbApi);
+
+ auto capability = std::make_shared<::testing::NiceMock<CapabilityMock>>();
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+ std::string capabilityName = "weather";
+
+ ON_CALL(*capability, getName()).WillByDefault(::testing::Return(capabilityName));
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ // We don't care if and how many times subscribe method is called on event.
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::NiceMock<AFBEventMock>());
+ ON_CALL(*mockEvent, subscribe(::testing::_)).WillByDefault(::testing::Return(true));
+ ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true));
+ auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ mockEvent->setName(eventName);
+ return mockEvent;
+ };
+
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator));
+
+ auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>();
+ std::string payload = "The answer to life the universe and everything = 42";
+
+ bool result = service->publish(capability, *upstreamEvents.begin(), payload);
+ ASSERT_FALSE(result); // Without subscribing to the event. Publish should fail.
+
+ result = service->subscribe(*request, capability, *upstreamEvents.begin());
+ ASSERT_TRUE(result);
+
+ result = service->subscribe(*request, capability, *downstreamEvents.begin());
+ ASSERT_TRUE(result);
+
+ result = service->publish(capability, *downstreamEvents.begin(), payload);
+ ASSERT_TRUE(result);
+}
+
+} // namespace test
+} // namespace vshl \ No newline at end of file
diff --git a/src/plugins/capabilities/test/PublisherForwarderTest.cpp b/src/plugins/capabilities/test/PublisherForwarderTest.cpp
new file mode 100644
index 0000000..8fb499c
--- /dev/null
+++ b/src/plugins/capabilities/test/PublisherForwarderTest.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 <gtest/gtest.h>
+
+#include "capabilities/core/include/PublisherForwarder.h"
+#include "capabilities/core/include/SubscriberForwarder.h"
+
+#include "test/common/ConsoleLogger.h"
+#include "test/mocks/AFBApiMock.h"
+#include "test/mocks/AFBEventMock.h"
+#include "test/mocks/CapabilityMock.h"
+
+using namespace vshlcapabilities::common::interfaces;
+using namespace vshlcapabilities::capabilities::core;
+using namespace vshlcapabilities::test::common;
+
+namespace vshlcapabilities {
+namespace test {
+
+class PublisherForwarderTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mConsoleLogger = std::make_shared<ConsoleLogger>();
+ mAfbApi = std::make_shared<::testing::StrictMock<AFBApiMock>>();
+
+ mEventCreatorFn = [](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ mockEvent->setName(eventName);
+ return mockEvent;
+ };
+ }
+
+ std::shared_ptr<SubscriberForwarder> createSubscriberForwarder(
+ std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) {
+ EXPECT_CALL(*capability, getUpstreamMessages()).Times(1);
+ EXPECT_CALL(*capability, getDownstreamMessages()).Times(1);
+
+ return SubscriberForwarder::create(mConsoleLogger, mAfbApi, capability);
+ }
+
+ std::shared_ptr<PublisherForwarder> createPublisherForwarder(
+ std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) {
+ return PublisherForwarder::create(mConsoleLogger, capability);
+ }
+
+ std::shared_ptr<::testing::StrictMock<AFBApiMock>> mAfbApi;
+ std::shared_ptr<ConsoleLogger> mConsoleLogger;
+ std::function<std::shared_ptr<IAFBApi::IAFBEvent>(const std::string&)> mEventCreatorFn;
+ std::shared_ptr<::testing::StrictMock<AFBEventMock>> mAfbEventMock;
+};
+
+TEST_F(PublisherForwarderTest, failsInitializationOnInvalidParams) {
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+
+ auto forwarder = PublisherForwarder::create(mConsoleLogger, nullptr);
+ ASSERT_EQ(forwarder, nullptr);
+
+ forwarder = PublisherForwarder::create(nullptr, capability);
+ ASSERT_EQ(forwarder, nullptr);
+}
+
+TEST_F(PublisherForwarderTest, initializesCorrectly) {
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ auto forwarder = createPublisherForwarder(capability);
+
+ ASSERT_NE(forwarder, nullptr);
+}
+
+TEST_F(PublisherForwarderTest, canForwardMessages) {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true));
+ EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(4);
+ auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ return mockEvent;
+ };
+
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto publisherForwarder = createPublisherForwarder(capability);
+ ASSERT_NE(publisherForwarder, nullptr);
+
+ auto subscriberForwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(subscriberForwarder, nullptr);
+
+ std::string payload = "The answer to life the universe and everything = 42";
+ publisherForwarder->setSubscriberForwarder(subscriberForwarder);
+
+ auto itCapability = downstreamEvents.begin();
+ ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload));
+ itCapability = upstreamEvents.begin();
+ ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload));
+}
+
+} // namespace test
+} // namespace vshl \ No newline at end of file
diff --git a/src/plugins/capabilities/test/SubscriberForwarderTest.cpp b/src/plugins/capabilities/test/SubscriberForwarderTest.cpp
new file mode 100644
index 0000000..c3d72de
--- /dev/null
+++ b/src/plugins/capabilities/test/SubscriberForwarderTest.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 <gtest/gtest.h>
+
+#include "capabilities/core/include/SubscriberForwarder.h"
+
+#include "test/common/ConsoleLogger.h"
+#include "test/mocks/AFBApiMock.h"
+#include "test/mocks/AFBEventMock.h"
+#include "test/mocks/AFBRequestMock.h"
+#include "test/mocks/CapabilityMock.h"
+
+using namespace vshlcapabilities::common::interfaces;
+using namespace vshlcapabilities::capabilities::core;
+using namespace vshlcapabilities::test::common;
+
+namespace vshlcapabilities {
+namespace test {
+
+class SubscriberForwarderTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mConsoleLogger = std::make_shared<ConsoleLogger>();
+ mAfbApi = std::make_shared<::testing::StrictMock<AFBApiMock>>();
+
+ mEventCreatorFn = [](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ mockEvent->setName(eventName);
+ return mockEvent;
+ };
+ }
+
+ std::shared_ptr<SubscriberForwarder> createSubscriberForwarder(
+ std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) {
+ EXPECT_CALL(*capability, getUpstreamMessages()).Times(1);
+ EXPECT_CALL(*capability, getDownstreamMessages()).Times(1);
+
+ return SubscriberForwarder::create(mConsoleLogger, mAfbApi, capability);
+ }
+
+ std::shared_ptr<::testing::StrictMock<AFBApiMock>> mAfbApi;
+ std::shared_ptr<ConsoleLogger> mConsoleLogger;
+ std::function<std::shared_ptr<IAFBApi::IAFBEvent>(const std::string&)> mEventCreatorFn;
+ std::shared_ptr<::testing::StrictMock<AFBEventMock>> mAfbEventMock;
+};
+
+TEST_F(SubscriberForwarderTest, failsInitializationOnInvalidParams) {
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+
+ auto forwarder = SubscriberForwarder::create(mConsoleLogger, mAfbApi, nullptr);
+ ASSERT_EQ(forwarder, nullptr);
+
+ forwarder = SubscriberForwarder::create(mConsoleLogger, nullptr, capability);
+ ASSERT_EQ(forwarder, nullptr);
+
+ forwarder = SubscriberForwarder::create(nullptr, mAfbApi, capability);
+ ASSERT_EQ(forwarder, nullptr);
+}
+
+TEST_F(SubscriberForwarderTest, initializesCorrectly) {
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ auto forwarder = createSubscriberForwarder(capability);
+
+ ASSERT_NE(forwarder, nullptr);
+}
+
+TEST_F(SubscriberForwarderTest, createsEventsOnInitialization) {
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(mEventCreatorFn));
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto itCapability = upstreamEvents.begin();
+ EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1);
+ itCapability++;
+ EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1);
+
+ itCapability = downstreamEvents.begin();
+ EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1);
+ itCapability++;
+ EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1);
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+}
+
+TEST_F(SubscriberForwarderTest, canNotSubscribeToNonExistentEvents) {
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(mEventCreatorFn));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto nonExistentEvents = std::list<std::string>({"non", "existent", "events"});
+ auto itCapability = nonExistentEvents.begin();
+ auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>();
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+}
+
+TEST_F(SubscriberForwarderTest, canNotSubscribeOnEventCreationFailure) {
+ // Fail the event creation and return null event.
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Return(nullptr));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto itCapability = downstreamEvents.begin();
+ auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>();
+ std::string payload = "The answer to life the universe and everything = 42";
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+ itCapability = upstreamEvents.begin();
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++));
+}
+
+TEST_F(SubscriberForwarderTest, canSubscribeToEvents) {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ ON_CALL(*mockEvent, subscribe(::testing::_)).WillByDefault(::testing::Return(true));
+ EXPECT_CALL(*mockEvent, subscribe(::testing::_)).Times(4);
+ auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ return mockEvent;
+ };
+
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto itCapability = downstreamEvents.begin();
+ auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>();
+ ASSERT_TRUE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_TRUE(forwarder->subscribe(*request, *itCapability));
+ itCapability = upstreamEvents.begin();
+ ASSERT_TRUE(forwarder->subscribe(*request, *itCapability++));
+ ASSERT_TRUE(forwarder->subscribe(*request, *itCapability));
+}
+
+TEST_F(SubscriberForwarderTest, canNotPublishNonExistentEvents) {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(0);
+ auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ return mockEvent;
+ };
+
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto nonExistentEvents = std::list<std::string>({"non", "existent", "events"});
+ auto itCapability = nonExistentEvents.begin();
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload"));
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload"));
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload"));
+}
+
+TEST_F(SubscriberForwarderTest, canNotPublishOnEventCreationFailure) {
+ // Fail the event creation and return null event.
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Return(nullptr));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto itCapability = downstreamEvents.begin();
+ std::string payload = "The answer to life the universe and everything = 42";
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload));
+ itCapability = upstreamEvents.begin();
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload));
+}
+
+TEST_F(SubscriberForwarderTest, canPublishEvents) {
+ std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>());
+ ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true));
+ EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(4);
+ auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> {
+ return mockEvent;
+ };
+
+ ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator));
+ EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4);
+
+ std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"});
+ std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"});
+
+ auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>();
+ ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents));
+ ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents));
+
+ auto forwarder = createSubscriberForwarder(capability);
+ ASSERT_NE(forwarder, nullptr);
+
+ auto itCapability = downstreamEvents.begin();
+ std::string payload = "The answer to life the universe and everything = 42";
+ ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload));
+ itCapability = upstreamEvents.begin();
+ ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload));
+ ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload));
+}
+
+} // namespace test
+} // namespace vshl \ No newline at end of file
diff --git a/src/plugins/cmake/gtest.cmake b/src/plugins/cmake/gtest.cmake
new file mode 100644
index 0000000..def6559
--- /dev/null
+++ b/src/plugins/cmake/gtest.cmake
@@ -0,0 +1,44 @@
+# gtest
+
+find_package(Threads REQUIRED)
+
+# Enable ExternalProject CMake module
+INCLUDE(ExternalProject)
+
+ExternalProject_Add(
+ gtest
+ URL https://github.com/google/googletest/archive/release-1.8.1.zip
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/gtest-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/gtest-build"
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD ON
+ LOG_CONFIGURE ON
+ LOG_BUILD ON
+)
+
+# Get GTest source and binary directories from CMake project
+ExternalProject_Get_Property(gtest source_dir binary_dir)
+
+# Create a libgtest target to be used as a dependency by test programs
+ADD_LIBRARY(libgtest INTERFACE)
+TARGET_INCLUDE_DIRECTORIES(libgtest
+ INTERFACE
+ ${source_dir}/googletest/include
+)
+TARGET_LINK_LIBRARIES(libgtest
+ INTERFACE
+ ${binary_dir}/googlemock/gtest/libgtest.a
+ ${CMAKE_THREAD_LIBS_INIT}
+)
+
+# Create a libgmock target to be used as a dependency by test programs
+ADD_LIBRARY(libgmock INTERFACE)
+TARGET_INCLUDE_DIRECTORIES(libgmock
+ INTERFACE
+ ${source_dir}/googlemock/include
+)
+TARGET_LINK_LIBRARIES(libgmock
+ INTERFACE
+ ${binary_dir}/googlemock/libgmock.a
+ ${CMAKE_THREAD_LIBS_INIT}
+) \ No newline at end of file
diff --git a/src/plugins/interfaces/afb/IAFBApi.h b/src/plugins/interfaces/afb/IAFBApi.h
new file mode 100644
index 0000000..b607fd8
--- /dev/null
+++ b/src/plugins/interfaces/afb/IAFBApi.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_COMMON_INTERFACES_AFBAPI_H_
+#define VSHL_COMMON_INTERFACES_AFBAPI_H_
+
+#include <memory>
+#include <string>
+
+#include <json-c/json_object.h>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace common {
+namespace interfaces {
+
+/**
+ * Interface to represent AFB Request.
+ */
+class IAFBRequest {
+public:
+ /**
+ * Gets the native request object.
+ */
+ virtual void* getNativeRequest() = 0;
+};
+
+/**
+ * Interface to encapsulate all AFB (AGL Application Framework Binding)
+ * functions.
+ */
+class IAFBApi {
+public:
+ /**
+ * Interface to represent AFB Event
+ */
+ class IAFBEvent {
+ public:
+ /**
+ * Gets human readable name of the event.
+ */
+ virtual std::string getName() const = 0;
+
+ /**
+ * Returns true if event is valid. False otherwise.
+ */
+ virtual bool isValid() = 0;
+
+ /**
+ * Publish event to all observers.
+ *
+ * @return The number of observers that received the event.
+ */
+ virtual int publishEvent(struct json_object* payload) = 0;
+
+ /**
+ * Subscribe to the event
+ *
+ * @c request Party interested in the event.
+ */
+ virtual bool subscribe(IAFBRequest& request) = 0;
+
+ /**
+ * Unsubscribe to the event
+ *
+ * @c request Party no longer interested in the event.
+ */
+ virtual bool unsubscribe(IAFBRequest& request) = 0;
+ };
+
+ virtual std::shared_ptr<IAFBEvent> createEvent(const std::string& eventName) = 0;
+
+ virtual int callSync(
+ const std::string& api,
+ const std::string& verb,
+ struct json_object* request,
+ struct json_object** result,
+ std::string& error,
+ std::string& info) = 0;
+};
+
+} // namespace interfaces
+} // namespace common
+} // namespace vshl
+
+#endif // VSHL_COMMON_INTERFACES_AFBAPI_H_
diff --git a/src/plugins/interfaces/capabilities/ICapability.h b/src/plugins/interfaces/capabilities/ICapability.h
new file mode 100644
index 0000000..ebdd4e8
--- /dev/null
+++ b/src/plugins/interfaces/capabilities/ICapability.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_COMMON_INTERFACES_ICAPABILITY_H_
+#define VSHL_COMMON_INTERFACES_ICAPABILITY_H_
+
+#include <list>
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace common {
+namespace interfaces {
+
+/*
+ * This interface defines the structure for a specific voiceagent capability.
+ */
+class ICapability {
+public:
+ /*
+ * Returns the capability's name.
+ */
+ virtual string getName() const = 0;
+
+ /*
+ * Returns the list of upstream messages.
+ */
+ virtual list<string> getUpstreamMessages() const = 0;
+
+ /*
+ * Returns the list of downstream messages
+ */
+ virtual list<string> getDownstreamMessages() const = 0;
+
+ /**
+ * Virtual destructor to assure proper cleanup of derived types.
+ */
+ virtual ~ICapability() = default;
+};
+
+} // namespace interfaces
+} // namespace common
+} // namespace vshl
+
+#endif // VSHL_COMMON_INTERFACES_ICAPABILITY_H_
diff --git a/src/plugins/interfaces/utilities/events/IEventFilter.h b/src/plugins/interfaces/utilities/events/IEventFilter.h
new file mode 100644
index 0000000..a4e3c64
--- /dev/null
+++ b/src/plugins/interfaces/utilities/events/IEventFilter.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_COMMON_INTERFACES_IEVENTFILTER_H_
+#define VSHL_COMMON_INTERFACES_IEVENTFILTER_H_
+
+#include <string>
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace common {
+namespace interfaces {
+/*
+ * This is an abstract class that is responsible for filtering the events
+ * that are delivered to the high level voice service from apps or voiceagents.
+ */
+class IEventFilter {
+public:
+ // Name of the event filter.
+ virtual string getName() = 0;
+
+ // Every event filter needs to implement this method and
+ // return true if consuming the event or false otherwise.
+ virtual bool onIncomingEvent(const string eventName, const string voiceAgentId, const string payload) = 0;
+
+ // Destructor
+ virtual ~IEventFilter() = default;
+};
+
+} // namespace interfaces
+} // namespace common
+} // namespace vshl
+
+#endif // VSHL_COMMON_INTERFACES_IEVENTFILTER_H_
diff --git a/src/plugins/interfaces/utilities/logging/ILogger.h b/src/plugins/interfaces/utilities/logging/ILogger.h
new file mode 100644
index 0000000..4cf25aa
--- /dev/null
+++ b/src/plugins/interfaces/utilities/logging/ILogger.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_COMMON_INTERFACES_LOGGER_H_
+#define VSHL_COMMON_INTERFACES_LOGGER_H_
+
+#include <string>
+
+namespace vshlcapabilities {
+namespace common {
+namespace interfaces {
+
+class ILogger {
+public:
+ enum Level {
+ DEBUG,
+ INFO,
+ WARNING,
+ ERROR,
+ NOTICE,
+ };
+
+ virtual void log(Level level, const std::string &tag,
+ const std::string &message) = 0;
+};
+
+} // namespace interfaces
+} // namespace common
+} // namespace vshl
+
+#endif // VSHL_COMMON_INTERFACES_LOGGER_H_
diff --git a/src/plugins/test/common/ConsoleLogger.cpp b/src/plugins/test/common/ConsoleLogger.cpp
new file mode 100644
index 0000000..a2a2598
--- /dev/null
+++ b/src/plugins/test/common/ConsoleLogger.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 <iostream>
+
+#include "test/common/ConsoleLogger.h"
+
+namespace vshlcapabilities {
+namespace test {
+namespace common {
+
+void ConsoleLogger::log(Level level, const std::string& tag, const std::string& message) {
+ string format_msg = "Tag: " + tag + ", message: " + message;
+ std::cout << format_msg << std::endl;
+}
+
+} // namespace common
+} // namespace test
+} // namespace vshl
diff --git a/src/plugins/test/common/ConsoleLogger.h b/src/plugins/test/common/ConsoleLogger.h
new file mode 100644
index 0000000..2f81086
--- /dev/null
+++ b/src/plugins/test/common/ConsoleLogger.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_TEST_COMMON_CONSOLE_LOGGER_H_
+#define VSHL_TEST_COMMON_CONSOLE_LOGGER_H_
+
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace test {
+namespace common {
+
+class ConsoleLogger : public vshlcapabilities::common::interfaces::ILogger {
+public:
+ // ILogger interface
+ void log(Level level, const std::string &tag,
+ const std::string &message) override;
+};
+
+} // namespace common
+} // namespace test
+} // namespace vshl
+
+#endif // VSHL_TEST_COMMON_CONSOLE_LOGGER_H_
diff --git a/src/plugins/test/mocks/AFBApiMock.h b/src/plugins/test/mocks/AFBApiMock.h
new file mode 100644
index 0000000..8cefa39
--- /dev/null
+++ b/src/plugins/test/mocks/AFBApiMock.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_TEST_MOCKS_AFBAPIMOCK_H_
+#define VSHL_TEST_MOCKS_AFBAPIMOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "interfaces/afb/IAFBApi.h"
+
+namespace vshlcapabilities {
+namespace test {
+
+class AFBApiMock : public vshlcapabilities::common::interfaces::IAFBApi {
+public:
+ MOCK_METHOD1(createEvent, std::shared_ptr<IAFBEvent>(const std::string& eventName));
+ MOCK_METHOD6(
+ callSync,
+ int(const std::string& api,
+ const std::string& verb,
+ struct json_object* request,
+ struct json_object** result,
+ std::string& error,
+ std::string& info));
+};
+
+} // namespace test
+} // namespace vshl
+
+#endif // VSHL_TEST_MOCKS_AFBAPIMOCK_H_ \ No newline at end of file
diff --git a/src/plugins/test/mocks/AFBEventMock.h b/src/plugins/test/mocks/AFBEventMock.h
new file mode 100644
index 0000000..f4e2b67
--- /dev/null
+++ b/src/plugins/test/mocks/AFBEventMock.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_TEST_MOCKS_AFBEVENTMOCK_H_
+#define VSHL_TEST_MOCKS_AFBEVENTMOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "interfaces/afb/IAFBApi.h"
+
+namespace vshlcapabilities {
+namespace test {
+
+class AFBEventMock : public vshlcapabilities::common::interfaces::IAFBApi::IAFBEvent {
+public:
+ void setName(const std::string& name) {
+ mName = name;
+ }
+
+ std::string getName() const override {
+ return mName;
+ }
+
+ MOCK_METHOD0(isValid, bool());
+ MOCK_METHOD1(publishEvent, int(struct json_object* payload));
+ MOCK_METHOD1(subscribe, bool(vshlcapabilities::common::interfaces::IAFBRequest& request));
+ MOCK_METHOD1(unsubscribe, bool(vshlcapabilities::common::interfaces::IAFBRequest& request));
+
+private:
+ std::string mName;
+};
+
+} // namespace test
+} // namespace vshl
+
+#endif // VSHL_TEST_MOCKS_AFBEVENTMOCK_H_ \ No newline at end of file
diff --git a/src/plugins/test/mocks/AFBRequestMock.h b/src/plugins/test/mocks/AFBRequestMock.h
new file mode 100644
index 0000000..0aaeede
--- /dev/null
+++ b/src/plugins/test/mocks/AFBRequestMock.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_
+#define VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "interfaces/afb/IAFBApi.h"
+
+namespace vshlcapabilities {
+namespace test {
+
+class AFBRequestMock : public vshlcapabilities::common::interfaces::IAFBRequest {
+public:
+ MOCK_METHOD0(getNativeRequest, void*());
+};
+
+} // namespace test
+} // namespace vshl
+
+#endif // VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_ \ No newline at end of file
diff --git a/src/plugins/test/mocks/CapabilityMock.h b/src/plugins/test/mocks/CapabilityMock.h
new file mode 100644
index 0000000..aaa0bd5
--- /dev/null
+++ b/src/plugins/test/mocks/CapabilityMock.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_TEST_MOCKS_CAPABILITYMOCK_H_
+#define VSHL_TEST_MOCKS_CAPABILITYMOCK_H_
+
+#include <gmock/gmock.h>
+
+#include "interfaces/capabilities/ICapability.h"
+
+namespace vshlcapabilities {
+namespace test {
+
+class CapabilityMock : public vshlcapabilities::common::interfaces::ICapability {
+public:
+ MOCK_CONST_METHOD0(getName, std::string());
+ MOCK_CONST_METHOD0(getUpstreamMessages, std::list<std::string>());
+ MOCK_CONST_METHOD0(getDownstreamMessages, std::list<std::string>());
+};
+
+} // namespace test
+} // namespace vshl
+
+#endif // VSHL_TEST_MOCKS_CAPABILITYMOCK_H_ \ No newline at end of file
diff --git a/src/plugins/utilities/events/EventRouter.cpp b/src/plugins/utilities/events/EventRouter.cpp
new file mode 100644
index 0000000..e715ca8
--- /dev/null
+++ b/src/plugins/utilities/events/EventRouter.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "utilities/events/EventRouter.h"
+
+static string TAG = "vshlcapabilities::utilities::events::EventRouter";
+
+using Level = vshlcapabilities::common::interfaces::ILogger::Level;
+
+namespace vshlcapabilities {
+namespace utilities {
+namespace events {
+
+unique_ptr<EventRouter> EventRouter::create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) {
+ return std::unique_ptr<EventRouter>(new EventRouter(logger));
+}
+
+EventRouter::EventRouter(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) : mLogger(logger) {
+}
+
+EventRouter::~EventRouter() {
+ mEventFilters.clear();
+}
+
+bool EventRouter::handleIncomingEvent(const string eventName, const string voiceAgentId, const string payload) {
+ for (auto eventFilter : mEventFilters) {
+ if (eventFilter->onIncomingEvent(eventName, voiceAgentId, payload)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool EventRouter::addEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter) {
+ if (!filter) {
+ mLogger->log(Level::ERROR, TAG, "Failed to add event filter. Invalid arguments.");
+ return false;
+ }
+
+ mEventFilters.insert(filter);
+ return true;
+}
+
+bool EventRouter::removeEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter) {
+ if (!filter) {
+ mLogger->log(Level::ERROR, TAG, "Failed to add remove filter. Invalid arguments.");
+ return false;
+ }
+
+ mEventFilters.erase(filter);
+ return true;
+}
+
+} // namespace events
+} // namespace utilities
+} // namespace vshl
diff --git a/src/plugins/utilities/events/EventRouter.h b/src/plugins/utilities/events/EventRouter.h
new file mode 100644
index 0000000..1286128
--- /dev/null
+++ b/src/plugins/utilities/events/EventRouter.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_UTILITIES_EVENTS_EVENTMANAGER_H_
+#define VSHL_UTILITIES_EVENTS_EVENTMANAGER_H_
+
+#include <memory>
+#include <string>
+#include <unordered_set>
+
+#include "interfaces/utilities/events/IEventFilter.h"
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace utilities {
+namespace events {
+/*
+ * This class is responsible for routing incoming events to
+ * the appropriate event listener for consumption.
+ * Note: The listeners should implement the IEventFilter class.
+ */
+class EventRouter {
+public:
+ static unique_ptr<EventRouter> create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ // Destructor
+ ~EventRouter();
+
+ // Add event filter as listerner.
+ bool addEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter);
+
+ // Remove event filter as listerner.
+ bool removeEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter);
+
+ // This method is called by the controller for routing
+ // the event to appropriate listener.
+ bool handleIncomingEvent(const string eventName, const string voiceAgentId, const string payload);
+
+private:
+ EventRouter(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger);
+
+ // set of event filters.
+ unordered_set<shared_ptr<vshlcapabilities::common::interfaces::IEventFilter>> mEventFilters;
+
+ // Logger
+ shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger;
+};
+
+} // namespace events
+} // namespace utilities
+} // namespace vshl
+
+#endif // VSHL_UTILITIES_EVENTS_EVENTROUTER_H_
diff --git a/src/plugins/utilities/logging/Logger.cpp b/src/plugins/utilities/logging/Logger.cpp
new file mode 100644
index 0000000..c121556
--- /dev/null
+++ b/src/plugins/utilities/logging/Logger.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 "utilities/logging/Logger.h"
+
+namespace vshlcapabilities {
+namespace utilities {
+namespace logging {
+
+// Constructor
+Logger::Logger(AFB_ApiT api) {
+ mApi = api;
+}
+
+unique_ptr<Logger> Logger::create(AFB_ApiT api) {
+ auto logger = std::unique_ptr<Logger>(new Logger(api));
+ return logger;
+}
+
+void Logger::log(Level level, const std::string& tag, const std::string& message) {
+ string format_msg = "Tag: " + tag + ", message: " + message;
+ switch (level) {
+ case Level::NOTICE:
+ AFB_ApiNotice(mApi, format_msg.c_str());
+ break;
+ case Level::WARNING:
+ AFB_ApiWarning(mApi, format_msg.c_str());
+ break;
+ case Level::DEBUG:
+ AFB_ApiDebug(mApi, format_msg.c_str());
+ break;
+ case Level::ERROR:
+ AFB_ApiError(mApi, format_msg.c_str());
+ break;
+ case Level::INFO:
+ AFB_ApiInfo(mApi, format_msg.c_str());
+ break;
+ default:
+ break;
+ }
+}
+
+} // namespace logging
+} // namespace utilities
+} // namespace vshl
diff --git a/src/plugins/utilities/logging/Logger.h b/src/plugins/utilities/logging/Logger.h
new file mode 100644
index 0000000..56f810d
--- /dev/null
+++ b/src/plugins/utilities/logging/Logger.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 VSHL_UTILITIES_LOGGING_LOGGER_H_
+#define VSHL_UTILITIES_LOGGING_LOGGER_H_
+
+#include <memory>
+
+extern "C" {
+#define AFB_BINDING_VERSION 3
+#include "afb-definitions.h"
+#include "ctl-plugin.h"
+};
+
+#include "interfaces/utilities/logging/ILogger.h"
+
+using namespace std;
+
+namespace vshlcapabilities {
+namespace utilities {
+namespace logging {
+
+class Logger : public vshlcapabilities::common::interfaces::ILogger {
+public:
+ static std::unique_ptr<Logger> create(AFB_ApiT api);
+
+ // ILogger interface
+ void log(Level level, const std::string &tag,
+ const std::string &message) override;
+
+private:
+ Logger(AFB_ApiT api);
+
+ // Binding API reference
+ AFB_ApiT mApi;
+};
+
+} // namespace logging
+} // namespace utilities
+} // namespace vshl
+
+#endif // VSHL_UTILITIES_LOGGING_LOGGER_H_
diff --git a/src/vshl-capabilities-apidef.h b/src/vshl-capabilities-apidef.h
new file mode 100644
index 0000000..6ce4cb3
--- /dev/null
+++ b/src/vshl-capabilities-apidef.h
@@ -0,0 +1,53 @@
+
+static const char _afb_description_vshl_capabilities[] =
+ "{\"openapi\":\"3.0.0\",\"$schema\":\"http://iot.bzh/download/openapi/sch"
+ "ema-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\""
+ "High Level Voice Service Capabilities APIs\",\"version\":\"0.1\",\"x-bin"
+ "ding-c-generator\":{\"api\":\"vshl-capabilities\",\"version\":3,\"prefix"
+ "\":\"afv_\",\"postfix\":\"\",\"start\":null,\"onevent\":null,\"init\":\""
+ "init\",\"scope\":\"\",\"private\":false,\"noconcurrency\":true}},\"serve"
+ "rs\":[{\"url\":\"ws://{host}:{port}/api/monitor\",\"description\":\"TS c"
+ "aching binding\",\"variables\":{\"host\":{\"default\":\"localhost\"},\"p"
+ "ort\":{\"default\":\"1234\"}},\"x-afb-events\":[{\"$ref\":\"#/components"
+ "/schemas/afb-event\"}]}],\"components\":{\"schemas\":{\"afb-reply\":{\"$"
+ "ref\":\"#/components/schemas/afb-reply-v3\"},\"afb-event\":{\"$ref\":\"#"
+ "/components/schemas/afb-event-v3\"},\"afb-reply-v3\":{\"title\":\"Generi"
+ "c response.\",\"type\":\"object\",\"required\":[\"jtype\",\"request\"],\""
+ "properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-reply\"},\""
+ "request\":{\"type\":\"object\",\"required\":[\"status\"],\"properties\":"
+ "{\"status\":{\"type\":\"string\"},\"info\":{\"type\":\"string\"},\"token"
+ "\":{\"type\":\"string\"},\"uuid\":{\"type\":\"string\"},\"reqid\":{\"typ"
+ "e\":\"string\"}}},\"response\":{\"type\":\"object\"}}},\"afb-event-v3\":"
+ "{\"type\":\"object\",\"required\":[\"jtype\",\"event\"],\"properties\":{"
+ "\"jtype\":{\"type\":\"string\",\"const\":\"afb-event\"},\"event\":{\"typ"
+ "e\":\"string\"},\"data\":{\"type\":\"object\"}}}},\"responses\":{\"200\""
+ ":{\"description\":\"A complex object array response\",\"content\":{\"app"
+ "lication/json\":{\"schema\":{\"$ref\":\"#/components/schemas/afb-reply\""
+ "}}}}}}}"
+;
+
+
+static const struct afb_verb_v3 _afb_verbs_vshl_capabilities[] = {
+ {
+ .verb = NULL,
+ .callback = NULL,
+ .auth = NULL,
+ .info = NULL,
+ .session = 0,
+ .vcbdata = NULL,
+ .glob = 0
+ }
+};
+
+const struct afb_binding_v3 afbBindingV3 = {
+ .api = "vshl-capabilities",
+ .specification = _afb_description_vshl_capabilities,
+ .info = "",
+ .verbs = _afb_verbs_vshl_capabilities,
+ .preinit = NULL,
+ .init = init,
+ .onevent = NULL,
+ .userdata = NULL,
+ .noconcurrency = 1
+};
+
diff --git a/src/vshl-capabilities-apidef.json b/src/vshl-capabilities-apidef.json
new file mode 100644
index 0000000..158bf5a
--- /dev/null
+++ b/src/vshl-capabilities-apidef.json
@@ -0,0 +1,109 @@
+{
+ "openapi": "3.0.0",
+ "$schema": "http://iot.bzh/download/openapi/schema-3.0/default-schema.json",
+ "info": {
+ "description": "",
+ "title": "High Level Voice Service Capabilities APIs",
+ "version": "0.1",
+ "x-binding-c-generator": {
+ "api": "vshl-capabilities",
+ "version": 3,
+ "prefix": "afv_",
+ "postfix": "",
+ "start": null,
+ "onevent": null,
+ "init": "init",
+ "scope": "",
+ "private": false,
+ "noconcurrency": true
+ }
+ },
+ "servers": [{
+ "url": "ws://{host}:{port}/api/monitor",
+ "description": "TS caching binding",
+ "variables": {
+ "host": {
+ "default": "localhost"
+ },
+ "port": {
+ "default": "1234"
+ }
+ },
+ "x-afb-events": [{
+ "$ref": "#/components/schemas/afb-event"
+ }]
+ }],
+ "components": {
+ "schemas": {
+ "afb-reply": {
+ "$ref": "#/components/schemas/afb-reply-v3"
+ },
+ "afb-event": {
+ "$ref": "#/components/schemas/afb-event-v3"
+ },
+ "afb-reply-v3": {
+ "title": "Generic response.",
+ "type": "object",
+ "required": ["jtype", "request"],
+ "properties": {
+ "jtype": {
+ "type": "string",
+ "const": "afb-reply"
+ },
+ "request": {
+ "type": "object",
+ "required": ["status"],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "info": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ },
+ "uuid": {
+ "type": "string"
+ },
+ "reqid": {
+ "type": "string"
+ }
+ }
+ },
+ "response": {
+ "type": "object"
+ }
+ }
+ },
+ "afb-event-v3": {
+ "type": "object",
+ "required": ["jtype", "event"],
+ "properties": {
+ "jtype": {
+ "type": "string",
+ "const": "afb-event"
+ },
+ "event": {
+ "type": "string"
+ },
+ "data": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "A complex object array response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/afb-reply"
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/vshl-capabilities-binding.c b/src/vshl-capabilities-binding.c
new file mode 100644
index 0000000..b38210a
--- /dev/null
+++ b/src/vshl-capabilities-binding.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 _GNU_SOURCE
+#include "vshl-capabilities-binding.h"
+
+afb_dynapi* AFB_default;
+
+// Config Section definition (note: controls section index should match handle
+// retrieval in HalConfigExec)
+static CtlSectionT ctrlSections[] = {{.key = "plugins", .loadCB = PluginConfig},
+ {.key = "controls", .loadCB = ControlConfig},
+ {.key = NULL}};
+
+static AFB_ApiVerbs ctrlApiVerbs[] = {
+ {.verb = NULL} /* marker for end of the array */
+};
+
+static int ctrlLoadStaticVerbs(afb_dynapi* apiHandle, AFB_ApiVerbs* verbs) {
+ int errcount = 0;
+
+ for (int idx = 0; verbs[idx].verb; idx++) {
+ errcount += afb_dynapi_add_verb(
+ apiHandle,
+ ctrlApiVerbs[idx].verb,
+ NULL,
+ ctrlApiVerbs[idx].callback,
+ (void*)&ctrlApiVerbs[idx],
+ ctrlApiVerbs[idx].auth,
+ 0);
+ }
+
+ return errcount;
+};
+
+// next generation dynamic API-V3 mode
+#include <signal.h>
+
+static int CtrlInitOneApi(AFB_ApiT apiHandle)
+{
+ CtlConfigT *ctrlConfig;
+
+ if(!apiHandle)
+ return -1;
+
+ // Retrieve section config from api handle
+ ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle);
+ if(!ctrlConfig)
+ return -2;
+
+ return CtlConfigExec(apiHandle, ctrlConfig);
+}
+
+static int ctrlLoadOneApi(void* cbdata, AFB_ApiT apiHandle) {
+ CtlConfigT* ctrlConfig = (CtlConfigT*)cbdata;
+
+ // save closure as api's data context
+ afb_dynapi_set_userdata(apiHandle, ctrlConfig);
+
+ // add static controls verbs
+ int err = ctrlLoadStaticVerbs(apiHandle, ctrlApiVerbs);
+ if (err) {
+ AFB_ApiError(apiHandle, "ctrlLoadStaticVerbs fail to register static V2 verbs");
+ return ERROR;
+ }
+
+ // load section for corresponding API
+ err = CtlLoadSections(apiHandle, ctrlConfig, ctrlSections);
+ if (err) {
+ AFB_ApiError(apiHandle, "CtlLoadSections fail to load the sections");
+ return ERROR;
+ }
+
+ // declare an event event manager for this API;
+ afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent);
+
+ // init API function (does not receive user closure ???
+ afb_dynapi_on_init(apiHandle, CtrlInitOneApi);
+
+ afb_dynapi_seal(apiHandle);
+ return err;
+}
+
+int afbBindingEntry(afb_dynapi* apiHandle) {
+ AFB_default = apiHandle;
+ AFB_ApiNotice(apiHandle, "Controller in afbBindingEntry");
+
+ const char* dirList = getenv("CONTROL_CONFIG_PATH");
+ if (!dirList) dirList = CONTROL_CONFIG_PATH;
+
+ const char* configPath = CtlConfigSearch(apiHandle, dirList, "");
+ if (!configPath) {
+ AFB_ApiError(apiHandle, "CtlPreInit: No %s* config found in %s ", GetBinderName(), dirList);
+ return ERROR;
+ }
+
+ // load config file and create API
+ CtlConfigT* ctrlConfig = CtlLoadMetaData(apiHandle, configPath);
+ if (!ctrlConfig) {
+ AFB_ApiError(apiHandle, "CtrlBindingDyn No valid control config file in:\n-- %s", configPath);
+ return ERROR;
+ }
+
+ if (!ctrlConfig->api) {
+ AFB_ApiError(apiHandle, "CtrlBindingDyn API Missing from metadata in:\n-- %s", configPath);
+ return ERROR;
+ }
+
+ AFB_ApiNotice(apiHandle, "Controller API='%s' info='%s'", ctrlConfig->api, ctrlConfig->info);
+
+ // create one API per config file (Pre-V3 return code ToBeChanged)
+ int status = afb_dynapi_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, ctrlLoadOneApi, ctrlConfig);
+
+ return status;
+}
diff --git a/src/vshl-capabilities-binding.h b/src/vshl-capabilities-binding.h
new file mode 100644
index 0000000..75e7c91
--- /dev/null
+++ b/src/vshl-capabilities-binding.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 _CTL_BINDING_INCLUDE_
+#define _CTL_BINDING_INCLUDE_
+
+#define AFB_BINDING_VERSION 3
+#include <ctl-config.h>
+
+#ifndef ERROR
+#define ERROR -1
+#endif
+
+#endif /* _CTL_BINDING_INCLUDE_ */ \ No newline at end of file
diff --git a/tools/pre-commit b/tools/pre-commit
new file mode 100755
index 0000000..87a9fc3
--- /dev/null
+++ b/tools/pre-commit
@@ -0,0 +1,140 @@
+#!/bin/bash
+
+# git pre-commit hook that runs an clang-format stylecheck.
+# Features:
+# - abort commit when commit does not comply with the style guidelines
+# - create a patch of the proposed style changes
+
+# modifications for clang-format by rene.milk@wwu.de
+# This file is part of a set of unofficial pre-commit hooks available
+# at github.
+# Link: https://gist.github.com/wangkuiyi/7379a242f0d4089eaa75
+
+
+##################################################################
+# SETTINGS
+# set path to clang-format binary
+CLANG_FORMAT="`which clang-format`"
+
+# remove any older patches from previous commits. Set to true or false.
+# DELETE_OLD_PATCHES=false
+DELETE_OLD_PATCHES=false
+
+# only parse files with the extensions in FILE_EXTS. Set to true or false.
+# if false every changed file in the commit will be parsed with clang-format.
+# if true only files matching one of the extensions are parsed with clang-format.
+# PARSE_EXTS=true
+PARSE_EXTS=true
+
+# file types to parse. Only effective when PARSE_EXTS is true.
+# FILE_EXTS=".c .h .cpp .hpp"
+FILE_EXTS=".c .h .cpp .hpp .cc .hh .cxx .m"
+
+##################################################################
+# There should be no need to change anything below this line.
+
+# Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac
+canonicalize_filename () {
+ local target_file=$1
+ local physical_directory=""
+ local result=""
+
+ # Need to restore the working directory after work.
+ pushd `pwd` > /dev/null
+
+ cd "$(dirname "$target_file")"
+ target_file=`basename $target_file`
+
+ # Iterate down a (possible) chain of symlinks
+ while [ -L "$target_file" ]
+ do
+ target_file=$(readlink "$target_file")
+ cd "$(dirname "$target_file")"
+ target_file=$(basename "$target_file")
+ done
+
+ # Compute the canonicalized name by finding the physical path
+ # for the directory we're in and appending the target file.
+ physical_directory=`pwd -P`
+ result="$physical_directory"/"$target_file"
+
+ # restore the working directory after work.
+ popd > /dev/null
+
+ echo "$result"
+}
+
+# exit on error
+set -e
+
+# check whether the given file matches any of the set extensions
+matches_extension() {
+ local filename=$(basename "$1")
+ local extension=".${filename##*.}"
+ local ext
+
+ for ext in $FILE_EXTS; do [[ "$ext" == "$extension" ]] && return 0; done
+
+ return 1
+}
+
+# necessary check for initial commit
+if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
+ against=HEAD
+else
+ # Initial commit: diff against an empty tree object
+ against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+fi
+
+if [ ! -x "$CLANG_FORMAT" ] ; then
+ printf "Error: clang-format executable not found.\n"
+ printf "Set the correct path in $(canonicalize_filename "$0").\n"
+ exit 1
+fi
+
+# create a random filename to store our generated patch
+prefix="pre-commit-clang-format"
+suffix="$(date +%s)"
+patch="/tmp/$prefix-$suffix.patch"
+
+# clean up any older clang-format patches
+$DELETE_OLD_PATCHES && rm -f /tmp/$prefix*.patch
+
+# create one patch containing all changes to the files
+git diff-index --cached --diff-filter=ACMR --name-only $against -- | while read file;
+do
+ # ignore file if we do check for file extensions and the file
+ # does not match any of the extensions specified in $FILE_EXTS
+ if $PARSE_EXTS && ! matches_extension "$file"; then
+ continue;
+ fi
+
+ # clang-format our sourcefile, create a patch with diff and append it to our $patch
+ # The sed call is necessary to transform the patch from
+ # --- $file timestamp
+ # +++ - timestamp
+ # to both lines working on the same file and having a a/ and b/ prefix.
+ # Else it can not be applied with 'git apply'.
+ "$CLANG_FORMAT" -style=file "$file" | \
+ diff -u "$file" - | \
+ sed -e "1s|--- |--- a/|" -e "2s|+++ -|+++ b/$file|" >> "$patch"
+done
+
+# if no patch has been generated all is ok, clean up the file stub and exit
+if [ ! -s "$patch" ] ; then
+ printf "Files in this commit comply with the clang-format rules.\n"
+ rm -f "$patch"
+ exit 0
+fi
+
+# a patch has been created, notify the user and exit
+printf "\nThe following differences were found between the code to commit "
+printf "and the clang-format rules:\n\n"
+cat "$patch"
+
+printf "\nYou can apply these changes with:\n git apply $patch\n"
+printf "(may need to be called from the root directory of your repository)\n"
+printf "Aborting commit. Apply changes and commit again or skip checking with"
+printf " --no-verify (not recommended).\n"
+
+exit 1