Shows how to access the timestamps of incoming samples.
#pragma once
#include <deque>
#include <unordered_map>
#ifndef ADTF_EXAMPLES_CID
#define ADTF_EXAMPLES_CID ".local.cid"
#endif
{
public:
"demo_timestamp_synchronizer.filter" ADTF_EXAMPLES_CID,
"TimeStamp Synchronizer");
public:
cDemoSynchronizerFilter();
~cDemoSynchronizerFilter() override;
private:
{
tStream(cDemoSynchronizerFilter& oFilter,
std::string_view strName,
bool bSynchronousProcessing):
m_oFilter(oFilter)
{
std::string(strName).c_str(), pType,
{
std::scoped_lock oLock(m_oMutex);
if (!m_bSamplesReceived && m_bForwardFirstTrigger)
{
pWriter->ManualTrigger();
m_bForwardFirstTrigger = false;
}
else
{
pReader->ReadAllAvailableItems();
if (bSynchronousProcessing)
{
m_oFilter.CheckQueue();
}
}
}, false);
pReader->RegisterExternalQueue(this);
pWriter = m_oFilter.CreateOutputPin<adtf::streaming::cRequestForwardingWriter>((std::string(strName) + "_out").c_str(), pType);
}
tStream(const tStream&) = delete;
tStream(tStream&&) = delete;
tResult Push(
const adtf::streaming::IStreamItem& oStreamItem, tTimeStamp )
override
{
std::scoped_lock oLock(m_oMutex);
if (!m_bSamplesReceived)
{
if (oStreamItem.
GetType() == adtf::streaming::IStreamItem::tType::StreamType)
{
adtf::ucom::object_ptr<const adtf::streaming::ant::IStreamType> pType;
{
pWriter->ChangeType(pType);
m_bForwardFirstTrigger = true;
}
}
else
{
m_bSamplesReceived = true;
}
}
m_oFilter.InsertQueueItem(oStreamItem, *this);
}
void Clear() override
{
}
tResult Pop(adtf::streaming::IStreamItem& )
override
{
}
adtf::streaming::cRequestForwardingWriter* pWriter = nullptr;
adtf::streaming::request_forwarding_reader<adtf::streaming::cExternalQueueSampleReader>* pReader = nullptr;
adtf::base::tNanoSeconds tmLastSampleTimeStamp;
cDemoSynchronizerFilter& m_oFilter;
bool m_bForwardFirstTrigger = false;
bool m_bSamplesReceived = false;
std::mutex m_oMutex;
};
using tStreams = std::unordered_map<std::string, tStream>;
tStreams m_oStreams;
struct tQueueItem
{
tQueueItem(adtf::base::tNanoSeconds tmTimeStamp,
const adtf::streaming::IStreamItem& oStreamItem,
tStream& oStream):
tmTimeStamp(tmTimeStamp),
oStreamItem(oStreamItem),
pStream(&oStream)
{
}
adtf::base::tNanoSeconds tmTimeStamp;
adtf::streaming::cStreamItem oStreamItem;
tStream* pStream;
};
tStreams::iterator GetOrCreateInputStream(const std::string& strName,
void InsertQueueItem(adtf::streaming::cStreamItem&& oStreamItem, tStream& oStream);
void CheckQueue();
void Clear();
void ForwardItem(tQueueItem& sItem);
std::mutex m_oQueueMutex;
std::deque<tQueueItem> m_oQueue;
adtf::ucom::object_ptr<adtf::ucom::IEventSource> m_pClockEventSource;
adtf::base::property_variable<int64_t> m_nQueueTransferStartTimeout = 20000;
adtf::base::property_variable<int64_t> m_nQueueTransferEndTimeout = 10000;
adtf::base::property_variable<bool> m_bSynchronousQueueProcessing = false;
};
A_UTILS_NS::cResult tResult
For backwards compatibility and to bring latest version into scope.
Definition result.h:736
#define RETURN_NOERROR
Return status ERR_NOERROR, which requires the calling function's return type to be tResult.
Definition result.h:29
#define RETURN_ERROR(code)
Return specific error code, which requires the calling function's return type to be tResult.
Definition result.h:42
#define IS_OK(s)
Check if result is OK.
Definition result.h:17
#define REQUIRE_INTERFACE(_interface)
Macro usable with ADTF_CLASS_DEPENDENCIES() to require mandatory interfaces.
Definition class_dependencies.h:36
#define ADTF_CLASS_DEPENDENCIES(...)
Add interface ids (string literals,.
Definition class_dependencies.h:61
#define ADTF_CLASS_ID_NAME(_class, _strcid, _strclabel)
Definition class_id.h:33
tResult Init(tInitStage eStage) override
tResult Shutdown(tInitStage eStage) override
virtual tResult RequestDynamicOutputPin(const char *strName, const ucom::ant::iobject_ptr< const streaming::ant::IStreamType > &pType)
virtual tResult RequestDynamicInputPin(const char *strName, const ucom::ant::iobject_ptr< const streaming::ant::IStreamType > &pType)
Definition reference_clock_intf.h:782
Interface to create a sample reader buffer.
Definition samplestreamer_intf.h:96
virtual tType GetType() const =0
virtual tResult GetStreamType(ucom::ant::iobject_ptr< const IStreamType > &pStreamType) const =0
Definition streamitem_intf.h:105
Definition request_forwarding.h:80
void AddWriter(cRequestForwardingWriter *pWriter)
Definition request_forwarding.h:87
Definition event_source_intf.h:27
virtual tResult HandleEvent(const IEventSource &oSource, const void *pvEventData)=0
Definition event_source_intf.h:72
ant::iobject_ptr< T > iobject_ptr
Alias always bringing the latest version of ant::iobject_ptr into scope.
Definition object_ptr_intf.h:437
A timestamp with nanosecond precision.
Definition chrono.h:23
#include "synchronizer_filter.h"
using namespace adtf::util;
cDemoSynchronizerFilter);
cDemoSynchronizerFilter::cDemoSynchronizerFilter()
{
if (!m_pClockEventSource)
{
THROW_ERROR_DESC(ERR_POINTER,
"Reference clock missing or not implementing IEventSource");
}
m_nQueueTransferStartTimeout.SetDescription("Reference timespan AFTER which all Samples within the queue will be forwarded when the time difference between the first and last Sample exceeds the property value.");
RegisterPropertyVariable("queue_transfer_start_timeout", m_nQueueTransferStartTimeout);
m_nQueueTransferEndTimeout.SetDescription("Reference timespan UNTIL which all Samples within the queue will be forwarded when the time difference between the first and last Sample will be below the property value.");
RegisterPropertyVariable("queue_transfer_end_timeout", m_nQueueTransferEndTimeout);
m_bSynchronousQueueProcessing.SetDescription("if activated, this will force the queue to be forwarded synchronously when a Trigger is received on one of the Input Pins and the queue forwarding conditions are met.");
RegisterPropertyVariable("synchronous_queue_processing", m_bSynchronousQueueProcessing);
{
for (auto& sStream: m_oStreams)
{
sStream.second.pReader->ReadAllAvailableItems();
}
CheckQueue();
});
SetDescription("process_queue", "Runner to periodically trigger the function which checks the queue.");
SetDescription("Use this filter to sort incoming samples according to their timestamp in Live setups (Online Mode).\n\n"
"Note: Do not use this filter in combination with a Player (Offline Mode).\n"
"For playback scenarios please use the 'sorted_by_timestamps' reader of the Player.");
SetHelpLink("$(ADTF_DIR)/doc/html/page_timestamp_synchronizer.html");
}
cDemoSynchronizerFilter::~cDemoSynchronizerFilter() = default;
tResult cDemoSynchronizerFilter::RequestDynamicInputPin(
const char* strName,
{
auto itStream = GetOrCreateInputStream(strName, pType);
itStream->second.pWriter->ChangeType(pType);
}
tResult cDemoSynchronizerFilter::RequestDynamicOutputPin(
const char* strName,
{
std::string strStreamName(strName);
const std::string_view strOutSuffix = "_out";
if (strStreamName.rfind(strOutSuffix) != strStreamName.size() - strOutSuffix.size())
{
RETURN_ERROR_DESC(ERR_INVALID_ARG,
"Invalid output pin name '%s'. Output pin names have to end with '_out'.", strName);
}
const auto strInputName = strStreamName.substr(0, strStreamName.size() - strOutSuffix.size());
GetOrCreateInputStream(strInputName, pType);
}
tResult cDemoSynchronizerFilter::Init(tInitStage eStage)
{
if (eStage == tInitStage::StagePostConnect)
{
}
}
tResult cDemoSynchronizerFilter::Shutdown(tInitStage eStage)
{
if (eStage == tInitStage::StagePostConnect)
{
Clear();
}
}
tResult cDemoSynchronizerFilter::HandleEvent(
const IEventSource& oSource,
const void* pvEventData)
{
if (&oSource == m_pClockEventSource.Get())
{
{
Clear();
}
}
}
cDemoSynchronizerFilter::tStreams::iterator cDemoSynchronizerFilter::GetOrCreateInputStream(const std::string& strName,
{
return m_oStreams.try_emplace(strName, *this, strName, pType, m_bSynchronousQueueProcessing).first;
}
tStream& oStream)
{
std::lock_guard<std::mutex> oGuard(m_oQueueMutex);
auto tmTimeStamp = oStream.tmLastSampleTimeStamp;
if (oStreamItem.GetType() == adtf::streaming::IStreamItem::tType::Sample)
{
if (
IS_OK(oStreamItem.GetSample(pSample)))
{
oStream.tmLastSampleTimeStamp = tmTimeStamp;
}
}
m_oQueue.emplace(
std::upper_bound(
m_oQueue.begin(),
m_oQueue.end(),
tmTimeStamp,
{
return tmTime < sItem.tmTimeStamp;
}
),
tmTimeStamp, std::move(oStreamItem), oStream
);
}
void cDemoSynchronizerFilter::CheckQueue()
{
std::lock_guard<std::mutex> oGuard(m_oQueueMutex);
if (m_oQueue.empty())
{
return;
}
if (m_oQueue.back().tmTimeStamp - m_oQueue.front().tmTimeStamp <
duration_cast<tNanoSeconds>(
static_cast<tTimeStamp
>(m_nQueueTransferStartTimeout)))
{
return;
}
while (!m_oQueue.empty() &&
m_oQueue.back().tmTimeStamp - m_oQueue.front().tmTimeStamp >=
duration_cast<tNanoSeconds>(
static_cast<tTimeStamp
>(m_nQueueTransferEndTimeout)))
{
ForwardItem(m_oQueue.front());
m_oQueue.pop_front();
}
}
void cDemoSynchronizerFilter::Clear()
{
std::lock_guard<std::mutex> oGuard(m_oQueueMutex);
while (!m_oQueue.empty())
{
auto& oFront = m_oQueue.front();
{
ForwardItem(oFront);
}
m_oQueue.pop_front();
}
}
void cDemoSynchronizerFilter::ForwardItem(cDemoSynchronizerFilter::tQueueItem& sItem)
{
switch (sItem.oStreamItem.GetType())
{
{
if (
IS_OK(sItem.oStreamItem.GetSample(pSample)))
{
sItem.pStream->pWriter->Write(pSample);
}
break;
}
{
if (
IS_OK(sItem.oStreamItem.GetStreamType(pType)))
{
sItem.pStream->pWriter->ChangeType(pType);
}
break;
}
default:
{
sItem.pStream->pWriter->ManualTrigger(sItem.tmTimeStamp);
break;
}
}
}
#define ADTF_PLUGIN(__plugin_identifier,...)
Definition adtf_plugin.h:29
#define THROW_ERROR_DESC(_code,...)
throws a tResult exception
Definition result.h:85
#define RETURN_ERROR_DESC(_code,...)
Same as RETURN_ERROR(_error) using a printf like parameter list for detailed error description.
Definition result.h:44
#define THROW_IF_FAILED(s)
throws if the expression returns a failed tResult
Definition result.h:88
@ EVENT_TimeResetEnd
Event describes the Time reset after a new time was set.
Definition reference_clock_intf.h:64
@ StreamType
item is a IStreamType. Mind: All StreamType changes will be queue too !!
Definition streamitem_intf.h:36
@ Sample
item is a queue item contains a ISample
Definition streamitem_intf.h:38
Base object pointer to realize binary compatible reference counting in interface methods.
Definition object_ptr_intf.h:112
Definition object_ptr.h:384
Namespace for the ADTF Base SDK.
Definition adtf_base_type_traits.h:13
DestinationTimeStamp duration_cast(const SourceTimeStamp &) noexcept
Duration cast base template to converted between different time resolution.
Definition chrono.h:155
Namespace for the ADTF Filter SDK.
Definition configurable_runner.h:18
Namespace for the ADTF Streaming SDK.
Definition bindingproxyinport.h:14
base::flash::tNanoSeconds get_sample_time(const ucom::ant::iobject_ptr< const ant::ISample > &pSample)
Namespace for the ADTF uCOM SDK.
Definition adtf_system.h:324
object_ptr< T > ucom_object_ptr_cast(object_ptr< T > oCasted)
Alias always bringing the latest version of ant::ucom_object_ptr_cast() into scope.
Definition object_ptr_utilities.h:104
Definition reference_clock_intf.h:83