Tutorial 3 : How to make a box plugin library (template included)

  • NB: Document written for OpenViBE 2.1.0 (19.11.2018)

Introduction

This tutorial describes how to make an OpenViBE plugin library (.so or  .dll) that can be loaded by Designer. A plugin library can contain one or more box plugins, such as users see in Designer. If you are developing several related box plugins, it can make sense to collect them together into one plugin. In this tutorial we provide a template archive containing the folders and files necessary for the creation of a new plugin library.

Prerequisites

From this point we assume that you have downloaded the sources of OpenViBE and already built the whole software using the provided scripts at least once.
For those who want to catch up, download the sources or checkout the code, and then follow the build instructions.

Coding Rules

If you eventually intend to contribute your plugin library sources to OpenViBE, it would be a good  idea to already initially make your code follow the Coding Rules, as this would be requested at the latest in the merging stage. Folders and filenames must not contain spaces.

  • Folder Name convention : folder-name

Directory structure

All plugin library directories in OpenViBE source tree follow a specific directory organization:

  • plugin-name
    • bci-examples : Any useful scenarios to create an example of BCI.
      this folder can contain the different scenarios (*.xml). As well as the scripts (lua, python …) if necessary.
      If the example is composed of several scenarios, the name of the files must indicate the order of launch of the scenarios. Ex:

      • 0-Monitoring.xml
      • 1-Acquisition.xml
      • 2-Classifier-Training.xml
      • 3-Online.xml
      • 4-Replay.xml
    • box-tutorials : this folder can contain the different scenarios (*.xml) to illustrate the boxes in the plugin. As well as the scripts (lua, python …) to use your boxes.
    • signals : This folder can contain the different signals your tutorials might need. Prefer generic types such as *.gdf or *.ov. For storage of matrices or streamed matrices you can use the CSV format. It is however not recommended to commit large binaries to git.
    • doc : This folder MUST contain the documentation of your plugin including the *.dox-part of your boxes. See Writing Box Documentation.
    • src : This folder must contain all source code of your boxes and algorithm.
    • test : This folder must contain all source code of your unit tests and scenario tests.
      This part is highly recommended. A good code is a tested code.
  • CMakeLists.txt : the CMakelist file describing how to build the plugin.

Making the CmakeList.txt

This CmakeList finds sources and dependencies and tells the compiler what to include and link. The CMakeLists.txt files are automatically parsed when you build your OpenViBE with the plugin.

Note: The following cmakelists includes a lot of commented out lines (for example). In a real cmakelists, its recommended to keep it tidy, and not include unnecessary dependencies or lines.

 CMakeList.txt(click here to show content)
 CMakeList.txt(click here to hide content)

PROJECT(openvibe-plugins-template)

SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})

FILE(GLOB_RECURSE source_files src/*.cpp src/*.hpp src/*.h src/*.inl src/*.c)
ADD_LIBRARY(${PROJECT_NAME} SHARED ${source_files}
# "../../../contrib/packages/wavelet2d/wavelet2s.h" # If You need Some files, you can add it here and
)
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
COMPILE_FLAGS "-DOVP_Exports -DOVP_Shared -D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE")

#INCLUDE_DIRECTORIES("../../../contrib/packages/wavelet2d") # If You need Some directories, you can add it here and

# ---------------------------------
# OpenVibe Modules (uncomment usefull package)
# ---------------------------------
# OpenViBE Base
#INCLUDE("FindOpenViBE")
#INCLUDE("FindOpenViBECommon")
#INCLUDE("FindOpenViBEToolkit")

# OpenViBE Module
#INCLUDE("FindOpenViBEModuleSystem")
#INCLUDE("FindOpenViBEModuleXML")
#INCLUDE("FindOpenViBEModuleEBML")
#INCLUDE("FindOpenViBEModuleCSV")
#INCLUDE("FindOpenViBEModuleSocket")
#INCLUDE("FindOpenViBEModuleCommunication")
#INCLUDE("FindOpenViBEModuleFS")

# OpenViBE Third Party
#INCLUDE("FindThirdPartyEigen")
#INCLUDE("FindThirdPartyITPP")
#INCLUDE("FindThirdPartyFFTW3")
#INCLUDE("FindThirdPartyBoost")
#INCLUDE("FindThirdPartyBoost_FileSystem")
#INCLUDE("FindThirdPartyBoost_Chrono")
#INCLUDE("FindThirdPartyExpat")
#INCLUDE("FindThirdPartyXerces")
#INCLUDE("FindThirdPartyWinsock2")
#INCLUDE("FindThirdPartyFTDI")
#INCLUDE("FindThirdPartyGTK")

# ---------------------------------
# Target macros
# Defines target operating system
# Defines target architecture
# Defines target compiler
# ---------------------------------
SET_BUILD_PLATFORM()

# -----------------------------
# Install files (uncomment usefull line)
# -----------------------------
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})

#INSTALL(DIRECTORY bci-tutorials/ DESTINATION ${DIST_DATADIR}/openvibe/scenarios/bci-tutorials/)
#INSTALL(DIRECTORY box-tutorials/ DESTINATION ${DIST_DATADIR}/openvibe/scenarios/box-tutorials/)
#INSTALL(DIRECTORY signals/ DESTINATION ${DIST_DATADIR}/openvibe/scenarios/signals/)

# ---------------------------------
# Test applications (uncomment to enable your test directory)
# ---------------------------------
#IF(OV_COMPILE_TESTS)
# ADD_SUBDIRECTORY(test)
#ENDIF(OV_COMPILE_TESTS)

Source Folder

With your boxes and algorithms source folder you must have two files : ovp_define.h and ovp_main.cpp

Note: The following examples should be updated to be consistent, i.e. that IDs actually refer to the box actual code included.

 ovp_define.h(click here to show content)
 ovp_define.h(click here to hide content)

#pragma once
// All define you need. For Ex : 
// #define OVP_TypeId_EpochAverageMethod            OpenViBE::CIdentifier(0x6530BDB1, 0xD057BBFE)

 ovp_main.cpp(click here to show content)
 ovp_main.cpp(click here to hide content)

#include <openvibe/ov_all.h>
#include "ovp_defines.h"
// Boxes Includes
#include "boxes/ovpCBoxAlgorithmMyBox.h"

OVP_Declare_Begin();
	// Register boxes
	OVP_Declare_New(OpenViBEPlugins::MyPlugin::ovpCBoxAlgorithmMyBoxDesc);
OVP_Declare_End();

Test Folder

Scenario Output Test

To write test specification for a simple Box, You can use DartTestfile.txt. In this case, you have to create a short scenario with output to compare with a reference output. The Test manager run the scenario quickly and compare the output with the ref.
For Example : The test is called MyTest (it’s an example, use an explicit name) they have a CSV on Input and a CSV on Output

  • MyTest-test.xml
  • MyTest-input.csv
  • MyTest-ref.csv
 DartTestfile.txt(click here to show content)
 DartTestfile.txt(click here to hide content)

IF(WIN32)
	SET(EXT cmd)
	SET(OS_FLAGS "--no-pause")
ELSE()
	SET(EXT sh)
	SET(OS_FLAGS "")
ENDIF()

############ 

SET(TEST_NAME MyTest)   # To compare CSV with correct name file it's the only line to change
SET(SCENARIO_TO_TEST "${TEST_NAME}-test.xml")

ADD_TEST(clean_${TEST_NAME}		"${CMAKE_COMMAND}" "-E" "remove" "-f" "${TEST_NAME}-output.csv")
ADD_TEST(run_${TEST_NAME}		"$ENV{OV_BINARY_PATH}/openvibe-designer.${EXT}" ${OS_FLAGS} "--no-session-management" "--invisible" "--play-fast" ${SCENARIO_TO_TEST})
ADD_TEST(compare_${TEST_NAME}	"$ENV{OV_BINARY_PATH}/test_thresholdDataComparison.${EXT}" ${OS_FLAGS} "${TEST_NAME}-output.csv" "${TEST_NAME}-ref.csv" 0.0001)

SET_TESTS_PROPERTIES(run_${TEST_NAME} PROPERTIES ATTACHED_FILES_ON_FAIL ${OV_CONFIG_SUBDIR})
SET_TESTS_PROPERTIES(compare_${TEST_NAME} PROPERTIES ATTACHED_FILES_ON_FAIL "${TEST_NAME}-output.csv")
SET_TESTS_PROPERTIES(compare_${TEST_NAME} PROPERTIES DEPENDS run_${TEST_NAME})
SET_TESTS_PROPERTIES(run_${TEST_NAME} PROPERTIES DEPENDS clean_${TEST_NAME})

##############

Unit Test

The Second type of test is more standard, OpenViBE Unit Test use Google Test Framework. You must add a short CMakeList.txt in test folder. The project name is test_ + pluginname

 CMakeList.txt(click here to show content)
 CMakeList.txt(click here to hide content)

PROJECT(test_template)

ADD_EXECUTABLE(${PROJECT_NAME} test_template.cpp
    #Add you src files
	#../src/myAlgorithm.cpp
	)

SET_BUILD_PLATFORM()

#INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../src/boxes") # if your source folder have subfolder

SET(GTEST_ROOT ${OV_DEPENDENCY_CMD_PATH}/${CMAKE_FIND_LIBRARY_PREFIXES}gtest)
FIND_PACKAGE(GTest REQUIRED)

TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${GTEST_BOTH_LIBRARIES})
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS})

# ---------------------------------
# OpenVibe Modules (uncomment usefull package)
# ---------------------------------
#INCLUDE("FindOpenViBE")
#..........

ADD_TEST(NAME test_myplugin COMMAND ${PROJECT_NAME})

OV_INSTALL_LAUNCH_SCRIPT(SCRIPT_PREFIX "${PROJECT_NAME}" EXECUTABLE_NAME  "${PROJECT_NAME}")
INSTALL(TARGETS ${PROJECT_NAME}
	RUNTIME DESTINATION ${DIST_BINDIR}
	LIBRARY DESTINATION ${DIST_LIBDIR}
	ARCHIVE DESTINATION ${DIST_LIBDIR})

Add your test to the toolchain

To add your test in OpenViBE toolchain, open the CTestTestfile.cmake in "OpenViBERootDir/extras/test/" and add your test dir path to the list.
Ex : subdirs("${CTEST_SOURCE_DIRECTORY}/externals/template/test")

Next call "ctest -T Test" in folder build/extras-Release/. If you have keep all subdir test have a coffee and after a while you have some lines like :

Start 10: clean_MyTest
Test #10: clean_MyTest ...........................   Passed    0.03 sec
Start 11: run_MyTest
Test #11: run_MyTest .............................   Passed    1.47 sec
Start 12: compare_MyTest
Test #12: compare_MyTest .........................   Passed    0.06 sec

Template zip folder

Here’s a folder that includes the plugin library folder structure we just described.

plugin-template

This entry was posted in Tutorials. Bookmark the permalink.