This guide explains how data can be generated respectively sources of data can be plugged in. After reading this guide, you will know:
A Streaming Source provides streaming data. The data can be generated by the Streaming Source itself or generated outside the ADTF world but transformed by the Streaming Source into a data format ADTF Components can handle. If you are looking for a more comprehensive explanation of what Streaming Sources are follow this link.
For this example we create a Streaming Source that emits characters in a defined interval. The CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
project (CharacterStreamingSource)
set (STREAMING_SOURCE_NAME happy_character_source)
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/happy_character_source.h)
file(WRITE happy_character_source.h)
endif()
if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/happy_character_source.cpp)
file(WRITE happy_character_source.cpp)
endif()
find_package(ADTF COMPONENTS systemsdk filtersdk REQUIRED)
# Adds the happy_character_source project to the Visual Studio solution, which when build
# creates a shared object called happy_character_source.adtfplugin
adtf_add_streaming_service(${STREAMING_SOURCE_NAME} happy_character_source.h happy_character_source.cpp)
# Adds the INSTALL project to the Visual Studio solution, which when build
# copies our Filter to the subdirectory given as the second argument into ${CMAKE_INSTALL_PREFIX}
adtf_install_filter(${STREAMING_SOURCE_NAME} src/examples/bin)
# Generate a plugindescription for our Streaming Source
adtf_create_plugindescription(
TARGET ${STREAMING_SOURCE_NAME}
PLUGIN_SUBDIR "src/examples/bin"
VERSION "0.8.15"
LICENSE "ADTF"
SUPPORT_MAIL "support@mycompany.org"
HOMEPAGE_URL "www.mycompany.org"
)
# Generate a documentation for our Streaming Source
adtf_convert_plugindescription_to_dox(
TARGET ${STREAMING_SOURCE_NAME}
DIRECTORY ${CMAKE_BINARY_DIR}/src/doxygen/generated
)
cmake-gui.exe
to open the graphical user interface
CMakeLists.txt
file)
build
folder (this is where all the build stuff goes)
Configure
button
Ungrouped Entries
and you will see that the value for
the variable ADTF_DIR
is not set.
To fix this click into the "Value" Column and fill in the path to your ADTF directory.
CMAKE
and search for the variable CMAKE_INSTALL_PREFIX
.
By default this variable points to an absolute path with administration privileges which can be a problem.
Set the variable also to your ADTF directory e.g. D:/ADTF/3.4.0
.
Configure
button
Generate
button
Open Project
button to start Visual Studio
happy_character_source.h
file and add this minimal Streaming Source declaration:
#pragma once
// Include all necessary headers from the ADTF SDK
#include <adtffiltersdk/adtf_filtersdk.h>
// We need the system sdk in order to be able to create timers, threads etc.
// Mind that this must not be used within filter implementations, as they
// should use Active Runners (Timer, Thread).
#include <adtfsystemsdk/adtf_systemsdk.h>
// For simplicity use the necessary namespaces
using namespace adtf::util;
using namespace adtf::ucom;
using namespace adtf::base;
using namespace adtf::streaming;
using namespace adtf::system;
using namespace adtf::mediadescription;
// A very simple streaming source that generates characters.
// To implement a Sample Streaming Source, subclass adtf::filter::cSampleStreamingSource
class cHappyCharacterSource: public adtf::filter::cSampleStreamingSource
{
public:
// This macros provides some meta information about our Source Implementation
// This will be exposed by the plugin class factory.
ADTF_CLASS_ID_NAME(cHappyCharacterSource,
"happy_character_receiver.streaming_source.adtf_guides.cid",
"Happy Character Receiver");
// This macro exposes our dependencies to the ADTF Tooling (Configuration Editor, etc.)
ADTF_CLASS_DEPENDENCIES(REQUIRE_INTERFACE(adtf::services::IKernel),
REQUIRE_INTERFACE(adtf::services::IReferenceClock));
public:
// We setup Pins and Runners in the constructor
cHappyCharacterSource();
// In this methods we create and destroy the kernel timer
tResult StartStreaming() override;
tResult StopStreaming() override;
private:
// This method is registered as callback for the timer.
void TimerFunc();
private:
// A property variable always reflects the value of a Property
property_variable<int64_t> m_nSpeed = 1000000;
// We need access to the reference clock, this is a shared pointer
object_ptr<adtf::services::IReferenceClock> m_pClock;
// This will create a timer for us.
kernel_timer m_oTimer;
// A writer where we can write our character samples to.
ISampleWriter* m_pWriter;
};
happy_character_source.cpp
file and add this minimal Streaming Source definition:
#include "happy_character_source.h"
#include <cstdlib> // for rand()
// The code behind the macro creates a plugin and the main entries to the plugin DLL or shared object.
// The cHappyCharacterSource will be available through the plugins class factory.
ADTF_PLUGIN("Happy Character Plugin", cHappyCharacterSource);
// This is our output data
struct tSimple
{
char cValue;
};
// and our source alphabet
static char aAlphabet[26] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
cHappyCharacterSource::cHappyCharacterSource()
{
// make sure our Property Variable is in sync with a Property.
m_nSpeed.SetDescription("Property for internal timer for data generation.");
RegisterPropertyVariable("speed", m_nSpeed);
// create a type definition from our existing struct definiton
auto oStructureDefiniton = structure<tSimple>("tSimple")
.Add("cValue", &tSimple::cValue);
// and our Output Pin.
m_pWriter = CreateOutputPin("charOut", oStructureDefiniton);
SetDescription("charOut", "Outcoming characters");
// set basic information about the component itself and purpose
SetDescription("This streaming source shows how to emit characters as stream.");
}
tResult cHappyCharacterSource::StartStreaming()
{
// do not forget to call the implementation of our base class.
RETURN_IF_FAILED(cSampleStreamingSource::StartStreaming());
// gain access to the reference clock interface.
RETURN_IF_FAILED(_runtime->GetObject(m_pClock));
// This timer calls repeatedly our function that contains the character generation logic
m_oTimer = kernel_timer(cString(get_named_graph_object_full_name(*this) + "::generation_timer"),
m_nSpeed, 0, &cHappyCharacterSource::TimerFunc, this);
if (!m_oTimer.Stoppable())
{
RETURN_ERROR_DESC(ERR_UNEXPECTED, "Unable to create kernel timer");
}
LOG_INFO("Generating characters...");
RETURN_NOERROR;
}
tResult cHappyCharacterSource::StopStreaming()
{
m_oTimer.Stop();
return cSampleStreamingSource::StopStreaming();
}
void cHappyCharacterSource::TimerFunc()
{
int nCharacter = rand() % 26;
char newValue = aAlphabet[nCharacter];
// We log the generated value to the console just until we have a streaming sink that
// can handle it for us.
LOG_INFO("GENERATING HAPPY CHARACTER: %c", newValue);
auto tmNow = m_pClock->GetStreamTimeNs();
// To create output data use the output_sample_data template
// This will handle sample allocation for you and you can use it just
// like its template parameter type.
output_sample_data<tSimple> oOutputData(tmNow, {newValue});
// Write it to the connected sample stream.
// Do not call any methods of output_sample_data after you have called Release() which
// hands over the sample instance.
m_pWriter->Write(oOutputData.Release());
// Send a trigger via the Output Pin and its connected sample stream.
// We need to do this since we are at the source of a Runner Pipe.
// Mind, that you do not need and should not trigger manually in Filter implementations.
m_pWriter->ManualTrigger(tmNow);
}
*.adtfplugin
*.plugindescription
files)happy_character_source.adtfplugin
and happy_character_source.plugindescription
in the src\examples\bin\debug
folder of your ADTF delivery.Fire up the Configuration Editor
Filter Graph Editor
tabComponents
tabHappy Character Source
from the Components
tab into the Filter Graph Editor
Project View
tabLaunch with ADTF Control
rl running
Congratulations! Now you can flood the ADTF system with any type of data
Have a look at Streaming Sinks to learn who are the consumers of data.