init
This commit is contained in:
+74
@@ -0,0 +1,74 @@
|
||||
#include "ovpCBoxAlgorithmClockStimulator.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
bool CBoxAlgorithmClockStimulator::initialize()
|
||||
{
|
||||
const double interstimulationInterval = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
|
||||
const double minInterstimulationInterval = 0.0001;
|
||||
OV_ERROR_UNLESS_KRF(!(interstimulationInterval < minInterstimulationInterval),
|
||||
"Invalid stimulation interval [" << interstimulationInterval << "] (expected value > " << minInterstimulationInterval << ")",
|
||||
Kernel::ErrorType::BadSetting);
|
||||
|
||||
m_stimulationInterval = interstimulationInterval;
|
||||
m_nSentStimulation = 0;
|
||||
|
||||
m_stimulationID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
|
||||
m_lastStimulationDate = 0;
|
||||
m_lastEndTime = 0;
|
||||
|
||||
m_encoder.initialize(*this, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmClockStimulator::uninitialize()
|
||||
{
|
||||
m_encoder.uninitialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmClockStimulator::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmClockStimulator::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
const uint64_t currentTime = getPlayerContext().getCurrentTime();
|
||||
|
||||
CStimulationSet stimulationSet;
|
||||
stimulationSet.setStimulationCount(0);
|
||||
|
||||
while (CTime(double(m_nSentStimulation + 1) * m_stimulationInterval).time() < currentTime)
|
||||
{
|
||||
m_nSentStimulation += 1;
|
||||
m_lastStimulationDate = CTime(double(m_nSentStimulation) * m_stimulationInterval).time();
|
||||
stimulationSet.appendStimulation(m_stimulationID, m_lastStimulationDate, 0);
|
||||
}
|
||||
|
||||
if (currentTime == 0)
|
||||
{
|
||||
m_encoder.encodeHeader();
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastEndTime, m_lastEndTime);
|
||||
}
|
||||
m_encoder.getInputStimulationSet() = &stimulationSet;
|
||||
|
||||
m_encoder.encodeBuffer();
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastEndTime, currentTime);
|
||||
|
||||
m_lastEndTime = currentTime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
class CBoxAlgorithmClockStimulator final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
uint64_t getClockFrequency() override { return (1LL << 32) * 32; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_ClockStimulator)
|
||||
|
||||
protected:
|
||||
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmClockStimulator> m_encoder;
|
||||
uint64_t m_stimulationID = 0;
|
||||
uint64_t m_lastStimulationDate = 0;
|
||||
uint64_t m_lastEndTime = 0;
|
||||
|
||||
uint64_t m_nSentStimulation = 0;
|
||||
double m_stimulationInterval = 0;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmClockStimulatorDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
void release() override { }
|
||||
CString getName() const override { return CString("Clock stimulator"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
|
||||
CString getShortDescription() const override { return CString("Periodic stimulation generator"); }
|
||||
CString getDetailedDescription() const override { return CString("Triggers stimulation at fixed frequency"); }
|
||||
CString getCategory() const override { return CString("Stimulation"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
|
||||
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_ClockStimulator; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmClockStimulator; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addOutput("Generated stimulations", OV_TypeId_Stimulations);
|
||||
prototype.addSetting("Interstimulation interval (in sec)", OV_TypeId_Float, "1.0");
|
||||
prototype.addSetting("Stimulation", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_00");
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_ClockStimulatorDesc)
|
||||
};
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
#include "ovpCBoxAlgorithmPlayerController.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
bool CBoxAlgorithmPlayerController::initialize()
|
||||
{
|
||||
m_stimulationID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
m_actionID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
|
||||
m_decoder = &this->getAlgorithmManager().getAlgorithm(this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder));
|
||||
m_decoder->initialize();
|
||||
|
||||
ip_buffer.initialize(m_decoder->getInputParameter(OVP_GD_Algorithm_StimulationDecoder_InputParameterId_MemoryBufferToDecode));
|
||||
op_stimulationSet.initialize(m_decoder->getOutputParameter(OVP_GD_Algorithm_StimulationDecoder_OutputParameterId_StimulationSet));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmPlayerController::uninitialize()
|
||||
{
|
||||
op_stimulationSet.uninitialize();
|
||||
ip_buffer.uninitialize();
|
||||
|
||||
if (m_decoder)
|
||||
{
|
||||
m_decoder->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_decoder);
|
||||
m_decoder = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmPlayerController::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmPlayerController::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
ip_buffer = boxContext.getInputChunk(0, i);
|
||||
m_decoder->process();
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedHeader)) { }
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedBuffer))
|
||||
{
|
||||
IStimulationSet* stimSet = op_stimulationSet;
|
||||
for (size_t j = 0; j < stimSet->getStimulationCount(); ++j)
|
||||
{
|
||||
if (stimSet->getStimulationIdentifier(j) == m_stimulationID)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "Received stimulation ["
|
||||
<< this->getTypeManager().getEnumerationEntryNameFromValue(OV_TypeId_Stimulation, m_stimulationID) << "] causing action ["
|
||||
<< this->getTypeManager().getEnumerationEntryNameFromValue(OV_TypeId_PlayerAction, m_actionID) << "]\n";
|
||||
|
||||
bool res = false;
|
||||
if (m_actionID == OV_TypeId_PlayerAction_Play.id()) { res = this->getPlayerContext().play(); }
|
||||
if (m_actionID == OV_TypeId_PlayerAction_Stop.id()) { res = this->getPlayerContext().stop(); }
|
||||
if (m_actionID == OV_TypeId_PlayerAction_Pause.id()) { res = this->getPlayerContext().pause(); }
|
||||
if (m_actionID == OV_TypeId_PlayerAction_Forward.id()) { res = this->getPlayerContext().forward(); }
|
||||
|
||||
OV_ERROR_UNLESS_KRF(res, "Failed to request player action ["
|
||||
<< this->getTypeManager().getEnumerationEntryNameFromValue(OV_TypeId_PlayerAction, m_actionID) << "]",
|
||||
Kernel::ErrorType::BadConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedEnd)) { }
|
||||
|
||||
boxContext.markInputAsDeprecated(0, i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
class CBoxAlgorithmPlayerController final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_PlayerController)
|
||||
|
||||
protected:
|
||||
|
||||
Kernel::IAlgorithmProxy* m_decoder = nullptr;
|
||||
Kernel::TParameterHandler<const IMemoryBuffer*> ip_buffer;
|
||||
Kernel::TParameterHandler<IStimulationSet*> op_stimulationSet;
|
||||
|
||||
uint64_t m_stimulationID = 0;
|
||||
uint64_t m_actionID = 0;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmPlayerControllerDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
void release() override { }
|
||||
CString getName() const override { return CString("Player Controller"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA"); }
|
||||
CString getShortDescription() const override { return CString("Controls the player execution"); }
|
||||
|
||||
CString getDetailedDescription() const override { return CString("Add some settings to configure the way you want to control the player"); }
|
||||
|
||||
CString getCategory() const override { return CString("Stimulation"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
|
||||
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_PlayerController; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmPlayerController; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Stimulations", OV_TypeId_Stimulations);
|
||||
prototype.addSetting("Stimulation name", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_00");
|
||||
prototype.addSetting("Action to perform", OV_TypeId_PlayerAction, OV_TypeId_PlayerAction_Pause.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_PlayerControllerDesc)
|
||||
};
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
#include "ovpCBoxAlgorithmStimulationMultiplexer.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
|
||||
bool CBoxAlgorithmStimulationMultiplexer::initialize()
|
||||
{
|
||||
const Kernel::IBox& staticBoxContext = this->getStaticBoxContext();
|
||||
|
||||
m_decoders.resize(staticBoxContext.getInputCount());
|
||||
size_t index = 0;
|
||||
for (auto& stimulationDecoder : m_decoders)
|
||||
{
|
||||
stimulationDecoder.initialize(*this, index);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
m_encoder.initialize(*this, 0);
|
||||
|
||||
m_decoderEndTimes = std::vector<uint64_t>(staticBoxContext.getInputCount(), 0ULL);
|
||||
|
||||
m_lastStartTime = 0;
|
||||
m_lastEndTime = 0;
|
||||
m_wasHeaderSent = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationMultiplexer::uninitialize()
|
||||
{
|
||||
for (auto& stimulationDecoder : m_decoders) { stimulationDecoder.uninitialize(); }
|
||||
|
||||
m_encoder.uninitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationMultiplexer::processInput(const size_t /*index*/)
|
||||
{
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationMultiplexer::process()
|
||||
{
|
||||
const Kernel::IBox& staticBoxContext = this->getStaticBoxContext();
|
||||
Kernel::IBoxIO& dynamicBoxContext = this->getDynamicBoxContext();
|
||||
|
||||
if (!m_wasHeaderSent)
|
||||
{
|
||||
m_encoder.encodeHeader();
|
||||
dynamicBoxContext.markOutputAsReadyToSend(0, m_lastEndTime, m_lastEndTime);
|
||||
m_wasHeaderSent = true;
|
||||
}
|
||||
|
||||
uint64_t earliestReceivedChunkEndTime = 0xffffffffffffffffULL;
|
||||
|
||||
for (size_t input = 0; input < staticBoxContext.getInputCount(); ++input)
|
||||
{
|
||||
for (size_t chunk = 0; chunk < dynamicBoxContext.getInputChunkCount(input); ++chunk)
|
||||
{
|
||||
m_decoders[input].decode(chunk);
|
||||
|
||||
if (m_decoders[input].isBufferReceived())
|
||||
{
|
||||
for (size_t stimulation = 0; stimulation < m_decoders[input].getOutputStimulationSet()->getStimulationCount(); ++stimulation)
|
||||
{
|
||||
m_stimulations.insert(std::make_pair(m_decoders[input].getOutputStimulationSet()->getStimulationDate(stimulation),
|
||||
std::make_tuple(
|
||||
m_decoders[input].getOutputStimulationSet()->getStimulationIdentifier(stimulation),
|
||||
m_decoders[input].getOutputStimulationSet()->getStimulationDate(stimulation),
|
||||
m_decoders[input].getOutputStimulationSet()->getStimulationDuration(stimulation))));
|
||||
}
|
||||
}
|
||||
|
||||
m_decoderEndTimes[input] = dynamicBoxContext.getInputChunkEndTime(input, chunk);
|
||||
}
|
||||
|
||||
if (earliestReceivedChunkEndTime > m_decoderEndTimes[input]) { earliestReceivedChunkEndTime = m_decoderEndTimes[input]; }
|
||||
}
|
||||
|
||||
if (earliestReceivedChunkEndTime >= m_lastEndTime)
|
||||
{
|
||||
m_encoder.getInputStimulationSet()->clear();
|
||||
|
||||
for (auto stimulation = m_stimulations.begin(); stimulation != m_stimulations.end();)
|
||||
{
|
||||
if (stimulation->first < earliestReceivedChunkEndTime)
|
||||
{
|
||||
m_encoder.getInputStimulationSet()->appendStimulation(std::get<0>(stimulation->second), std::get<1>(stimulation->second),
|
||||
std::get<2>(stimulation->second));
|
||||
stimulation = m_stimulations.erase(stimulation);
|
||||
}
|
||||
else { ++stimulation; }
|
||||
}
|
||||
|
||||
m_encoder.encodeBuffer();
|
||||
|
||||
dynamicBoxContext.markOutputAsReadyToSend(0, m_lastEndTime, earliestReceivedChunkEndTime);
|
||||
|
||||
m_lastStartTime = m_lastEndTime;
|
||||
m_lastEndTime = earliestReceivedChunkEndTime;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
class CBoxAlgorithmStimulationMultiplexer final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { delete this; }
|
||||
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_StimulationMultiplexer)
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Toolkit::TStimulationDecoder<CBoxAlgorithmStimulationMultiplexer>> m_decoders;
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmStimulationMultiplexer> m_encoder;
|
||||
|
||||
std::vector<uint64_t> m_decoderEndTimes;
|
||||
|
||||
uint64_t m_lastStartTime = 0;
|
||||
uint64_t m_lastEndTime = 0;
|
||||
bool m_wasHeaderSent = false;
|
||||
|
||||
std::multimap<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> m_stimulations;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStimulationMultiplexerListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
bool check(Kernel::IBox& box) const
|
||||
{
|
||||
for (size_t input = 0; input < box.getInputCount(); ++input)
|
||||
{
|
||||
box.setInputName(input, ("Input stimulations " + std::to_string(input + 1)).c_str());
|
||||
box.setInputType(input, OV_TypeId_Stimulations);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onInputRemoved(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
|
||||
bool onInputAdded(Kernel::IBox& box, const size_t /*index*/) override { return this->check(box); }
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStimulationMultiplexerDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return CString("Stimulation multiplexer"); }
|
||||
CString getAuthorName() const override { return CString("Yann Renard"); }
|
||||
CString getAuthorCompanyName() const override { return CString("INRIA/IRISA"); }
|
||||
CString getShortDescription() const override { return CString("Merges several stimulation streams into one."); }
|
||||
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return CString(
|
||||
"The stimulations are ordered according to their start date. Thus each time all the input have chunks covering a period of time, a new output chunk is sent. This box may eventually produce output chunk reflecting a different duration depending on the inputs.");
|
||||
}
|
||||
|
||||
CString getCategory() const override { return CString("Streaming"); }
|
||||
CString getVersion() const override { return CString("1.1"); }
|
||||
CString getStockItemName() const override { return CString("gtk-sort-ascending"); }
|
||||
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
|
||||
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_StimulationMultiplexer; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmStimulationMultiplexer; }
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmStimulationMultiplexerListener; }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input stimulations 1", OV_TypeId_Stimulations);
|
||||
prototype.addInput("Input stimulations 2", OV_TypeId_Stimulations);
|
||||
prototype.addOutput("Multiplexed stimulations", OV_TypeId_Stimulations);
|
||||
prototype.addFlag(Kernel::BoxFlag_CanAddInput);
|
||||
prototype.addInputSupport(OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_StimulationMultiplexerDesc)
|
||||
};
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
#include "ovpCBoxAlgorithmStimulationVoter.h"
|
||||
|
||||
#include <system/ovCMath.h>
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
bool CBoxAlgorithmStimulationVoter::initialize()
|
||||
{
|
||||
const Kernel::IBox& boxContext = this->getStaticBoxContext();
|
||||
|
||||
OV_ERROR_UNLESS_KRF(boxContext.getInputCount() == 1, "Invalid number of inputs [" << boxContext.getInputCount() << "] (expected 1 single input)",
|
||||
Kernel::ErrorType::BadInput);
|
||||
|
||||
CIdentifier typeID;
|
||||
boxContext.getInputType(0, typeID);
|
||||
|
||||
OV_ERROR_UNLESS_KRF(typeID == OV_TypeId_Stimulations, "Invalid input type [" << typeID.str() << "] (expected OV_TypeId_Stimulations type)",
|
||||
Kernel::ErrorType::BadInput);
|
||||
|
||||
m_encoder = &this->getAlgorithmManager().getAlgorithm(this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationEncoder));
|
||||
m_encoder->initialize();
|
||||
|
||||
m_decoder = &this->getAlgorithmManager().getAlgorithm(this->getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationDecoder));
|
||||
m_decoder->initialize();
|
||||
|
||||
ip_buffer.initialize(m_decoder->getInputParameter(OVP_GD_Algorithm_StimulationDecoder_InputParameterId_MemoryBufferToDecode));
|
||||
op_stimulationSet.initialize(m_decoder->getOutputParameter(OVP_GD_Algorithm_StimulationDecoder_OutputParameterId_StimulationSet));
|
||||
|
||||
m_minimumVotes = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0);
|
||||
m_timeWindow = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
m_clearVotes = uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 2));
|
||||
m_outputDateMode = uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 3));
|
||||
m_rejectClassLabel = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 4);
|
||||
m_rejectClassCanWin = uint64_t(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 5));
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Vote clear mode " << m_clearVotes << ", timestamp at " << m_outputDateMode << ", reject mode " <<
|
||||
m_rejectClassCanWin << "\n";
|
||||
|
||||
m_latestStimulusDate = 0;
|
||||
m_lastTime = 0;
|
||||
|
||||
m_oStimulusDeque.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationVoter::uninitialize()
|
||||
{
|
||||
m_decoder->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_decoder);
|
||||
|
||||
m_encoder->uninitialize();
|
||||
this->getAlgorithmManager().releaseAlgorithm(*m_encoder);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationVoter::processInput(const size_t /*index*/)
|
||||
{
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStimulationVoter::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
Kernel::TParameterHandler<IStimulationSet*> ip_stimSet(m_encoder->getInputParameter(OVP_GD_Algorithm_StimulationEncoder_InputParameterId_StimulationSet));
|
||||
Kernel::TParameterHandler<IMemoryBuffer*> op_buffer(m_encoder->getOutputParameter(OVP_GD_Algorithm_StimulationEncoder_OutputParameterId_EncodedMemoryBuffer));
|
||||
op_buffer = boxContext.getOutputChunk(0);
|
||||
|
||||
// Push the stimulations to a queue
|
||||
bool newStimulus = false;
|
||||
for (size_t j = 0; j < boxContext.getInputChunkCount(0); ++j)
|
||||
{
|
||||
ip_buffer = boxContext.getInputChunk(0, j);
|
||||
m_decoder->process();
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedHeader)) { }
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedBuffer))
|
||||
{
|
||||
for (size_t k = 0; k < op_stimulationSet->getStimulationCount(); ++k)
|
||||
{
|
||||
uint64_t stimulationId = op_stimulationSet->getStimulationIdentifier(k);
|
||||
uint64_t stimulationDate = op_stimulationSet->getStimulationDate(k);
|
||||
m_latestStimulusDate = std::max(m_latestStimulusDate, stimulationDate);
|
||||
if (CTime(m_latestStimulusDate - stimulationDate).toSeconds() <= m_timeWindow)
|
||||
{
|
||||
// Stimulus is fresh, append
|
||||
m_oStimulusDeque.push_back(std::pair<uint64_t, uint64_t>(stimulationId, stimulationDate));
|
||||
newStimulus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_decoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationDecoder_OutputTriggerId_ReceivedEnd)) { }
|
||||
boxContext.markInputAsDeprecated(0, j);
|
||||
}
|
||||
|
||||
if (m_oStimulusDeque.empty() || !newStimulus) { return true; }
|
||||
|
||||
// Always clear too old votes that have slipped off the time window. The time window is relative to the time of the latest stimulus received.
|
||||
while (!m_oStimulusDeque.empty())
|
||||
{
|
||||
const uint64_t frontDate = m_oStimulusDeque.front().second;
|
||||
if (CTime(m_latestStimulusDate - frontDate).toSeconds() > m_timeWindow)
|
||||
{
|
||||
// Drop it
|
||||
m_oStimulusDeque.pop_front();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume stimuli are received in time order. Since the stimulus at the head wasn't too old, the rest aren't either
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Queue size is " << m_oStimulusDeque.size() << "\n";
|
||||
|
||||
if (m_oStimulusDeque.size() < m_minimumVotes)
|
||||
{
|
||||
// Not enough stimuli to vote
|
||||
return true;
|
||||
}
|
||||
|
||||
std::map<uint64_t, uint64_t> lastSeen; // The last occurrence of each type in time
|
||||
std::map<uint64_t, size_t> votes; // Histogram of votes
|
||||
|
||||
// Make a histogram of the votes
|
||||
for (const auto& stim : m_oStimulusDeque)
|
||||
{
|
||||
const uint64_t type = stim.first;
|
||||
const uint64_t date = stim.second;
|
||||
|
||||
votes[type]++;
|
||||
lastSeen[type] = std::max(lastSeen[type], date);
|
||||
// Never pop here, only pop on expiration
|
||||
}
|
||||
|
||||
// Find the winner
|
||||
uint64_t resultClassLabel = m_rejectClassLabel;
|
||||
size_t maxVotes = 0;
|
||||
|
||||
for (const auto& vote : votes)
|
||||
{
|
||||
const uint64_t type = vote.first;
|
||||
const size_t nVotes = vote.second; // can not be zero by construction above
|
||||
|
||||
if (m_rejectClassCanWin == OVP_TypeId_Voting_RejectClass_CanWin_No && type == m_rejectClassLabel)
|
||||
{
|
||||
// Reject class never wins
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nVotes > maxVotes)
|
||||
{
|
||||
resultClassLabel = type;
|
||||
maxVotes = nVotes;
|
||||
}
|
||||
else if (nVotes == maxVotes)
|
||||
{
|
||||
// Break ties arbitrarily
|
||||
if (System::Math::random0To1() > 0.5)
|
||||
{
|
||||
resultClassLabel = type;
|
||||
maxVotes = nVotes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_lastTime == 0)
|
||||
{
|
||||
m_encoder->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeHeader);
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastTime, m_lastTime);
|
||||
}
|
||||
|
||||
if (m_rejectClassCanWin == OVP_TypeId_Voting_RejectClass_CanWin_No && resultClassLabel == m_rejectClassLabel)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Winning class " << resultClassLabel << " was 'rejected' with " << maxVotes << "votes. Dropped.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64_t currentTime = getPlayerContext().getCurrentTime();
|
||||
|
||||
uint64_t timeStamp;
|
||||
if (m_outputDateMode == OVP_TypeId_Voting_OutputTime_Vote) { timeStamp = currentTime; }
|
||||
else if (m_outputDateMode == OVP_TypeId_Voting_OutputTime_Winner) { timeStamp = lastSeen[resultClassLabel]; }
|
||||
else { timeStamp = m_latestStimulusDate; }
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Debug << "Appending winning stimulus " << resultClassLabel << " at " << timeStamp << " (" << maxVotes << " votes)\n";
|
||||
|
||||
ip_stimSet->setStimulationCount(0);
|
||||
ip_stimSet->appendStimulation(resultClassLabel, timeStamp, 0);
|
||||
m_encoder->process(OVP_GD_Algorithm_StimulationEncoder_InputTriggerId_EncodeBuffer);
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastTime, currentTime);
|
||||
m_lastTime = currentTime;
|
||||
|
||||
if (m_clearVotes == OVP_TypeId_Voting_ClearVotes_AfterOutput) { m_oStimulusDeque.clear(); }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
class CBoxAlgorithmStimulationVoter final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_StimulationVoter)
|
||||
|
||||
protected:
|
||||
|
||||
uint64_t m_minimumVotes = 0;
|
||||
double m_timeWindow = 0;
|
||||
uint64_t m_rejectClassLabel = 0;
|
||||
CIdentifier m_clearVotes = CIdentifier::undefined();
|
||||
CIdentifier m_outputDateMode = CIdentifier::undefined();
|
||||
CIdentifier m_rejectClassCanWin = CIdentifier::undefined();
|
||||
|
||||
private:
|
||||
|
||||
Kernel::IAlgorithmProxy* m_encoder = nullptr;
|
||||
Kernel::IAlgorithmProxy* m_decoder = nullptr;
|
||||
Kernel::TParameterHandler<const IMemoryBuffer*> ip_buffer;
|
||||
Kernel::TParameterHandler<IStimulationSet*> op_stimulationSet;
|
||||
|
||||
std::deque<std::pair<uint64_t, uint64_t>> m_oStimulusDeque; // <label,time>
|
||||
|
||||
uint64_t m_latestStimulusDate = 0;
|
||||
uint64_t m_lastTime = 0;
|
||||
};
|
||||
|
||||
|
||||
class CBoxAlgorithmStimulationVoterListener final : public Toolkit::TBoxListener<IBoxListener>
|
||||
{
|
||||
public:
|
||||
|
||||
CBoxAlgorithmStimulationVoterListener() : m_inputTypeID(OV_TypeId_Stimulations) { }
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxListener<IBoxListener>, CIdentifier::undefined())
|
||||
|
||||
protected:
|
||||
|
||||
CIdentifier m_inputTypeID = CIdentifier::undefined();
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStimulationVoterDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
void release() override { }
|
||||
CString getName() const override { return CString("Stimulation Voter"); }
|
||||
CString getAuthorName() const override { return CString("Jussi T. Lindgren"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Inria"); }
|
||||
CString getShortDescription() const override { return CString("Performs majority vote on the input stimuli"); }
|
||||
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return CString(
|
||||
"Votes the most frequent stimulus ID in a given time window. Outputs the winning stimulus type. Several options are possible. To process multiple inputs, use Stimulation Multiplexer first.");
|
||||
}
|
||||
|
||||
CString getCategory() const override { return CString("Streaming"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
|
||||
CString getAddedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_StimulationVoter; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmStimulationVoter; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Stimulus input", OV_TypeId_Stimulations);
|
||||
prototype.addOutput("Selected stimulus", OV_TypeId_Stimulations);
|
||||
prototype.addSetting("Number of stimuli required for vote", OV_TypeId_Integer, "4");
|
||||
prototype.addSetting("Time window (secs)", OV_TypeId_Float, "2");
|
||||
prototype.addSetting("Clear votes", OVP_TypeId_Voting_ClearVotes, "After output");
|
||||
prototype.addSetting("Output timestamp", OVP_TypeId_Voting_OutputTime, "Time of last voting stimulus");
|
||||
prototype.addSetting("Reject class label", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_00");
|
||||
prototype.addSetting("Reject class can win", OVP_TypeId_Voting_RejectClass_CanWin, "No");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IBoxListener* createBoxListener() const override { return new CBoxAlgorithmStimulationVoterListener; }
|
||||
void releaseBoxListener(IBoxListener* listener) const override { delete listener; }
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_StimulationVoterDesc)
|
||||
};
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
#include "ovpCBoxAlgorithmStreamEndDetector.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
bool CBoxAlgorithmStreamEndDetector::initialize()
|
||||
{
|
||||
m_stimulationID = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), settingStimulationNameID());
|
||||
|
||||
OV_FATAL_UNLESS_K(this->getStaticBoxContext().getInterfacorIndex(Kernel::EBoxInterfacorType::Input, inputEBMLId(), m_inputEBMLIdx),
|
||||
"Box does not have input with identifier " << inputEBMLId(), Kernel::ErrorType::Internal);
|
||||
OV_FATAL_UNLESS_K(this->getStaticBoxContext().getInterfacorIndex(Kernel::EBoxInterfacorType::Output, outputStimulationsID(), m_outputStimulationsIdx),
|
||||
"Box does not have output with identifier " << outputStimulationsID(), Kernel::ErrorType::Internal);
|
||||
|
||||
m_decoder.initialize(*this, m_inputEBMLIdx);
|
||||
m_encoder.initialize(*this, m_outputStimulationsIdx);
|
||||
|
||||
m_isHeaderSent = false;
|
||||
m_endDate = 0;
|
||||
m_currentChunkEndDate = 0;
|
||||
m_endState = EEndState::WaitingForEnd;
|
||||
m_previousTime = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStreamEndDetector::uninitialize()
|
||||
{
|
||||
m_decoder.uninitialize();
|
||||
m_encoder.uninitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStreamEndDetector::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBoxAlgorithmStreamEndDetector::process()
|
||||
{
|
||||
Kernel::IBoxIO& dynamicBoxContext = this->getDynamicBoxContext();
|
||||
|
||||
for (size_t chunk = 0; chunk < dynamicBoxContext.getInputChunkCount(m_inputEBMLIdx); ++chunk)
|
||||
{
|
||||
OV_ERROR_UNLESS_KRF(m_decoder.decode(chunk), "Failed to decode chunk", Kernel::ErrorType::Internal);
|
||||
|
||||
// We can not receive anything before this date anymore, thus we can send an empty stream
|
||||
m_currentChunkEndDate = dynamicBoxContext.getInputChunkStartTime(m_inputEBMLIdx, chunk);
|
||||
if (m_decoder.isEndReceived())
|
||||
{
|
||||
m_endState = EEndState::EndReceived;
|
||||
m_endDate = dynamicBoxContext.getInputChunkEndTime(m_inputEBMLIdx, chunk);
|
||||
// As this is the last chunk, we make it so it ends at the same time as the received End chunk
|
||||
m_currentChunkEndDate = dynamicBoxContext.getInputChunkEndTime(m_inputEBMLIdx, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_isHeaderSent)
|
||||
{
|
||||
m_encoder.encodeHeader();
|
||||
this->getDynamicBoxContext().markOutputAsReadyToSend(0, 0, 0);
|
||||
m_isHeaderSent = true;
|
||||
}
|
||||
|
||||
IStimulationSet* stimulationSet = m_encoder.getInputStimulationSet();
|
||||
stimulationSet->clear();
|
||||
|
||||
|
||||
// If the timeout is reached we send the stimulation on the output 0
|
||||
if (m_endState == EEndState::EndReceived)
|
||||
{
|
||||
stimulationSet->appendStimulation(m_stimulationID, m_endDate, 0);
|
||||
m_endState = EEndState::StimulationSent;
|
||||
}
|
||||
|
||||
if (m_endState != EEndState::Finished && (m_endState == EEndState::StimulationSent || m_previousTime != m_currentChunkEndDate))
|
||||
{
|
||||
// we need to send an empty chunk even if there's no stim
|
||||
m_encoder.encodeBuffer();
|
||||
this->getDynamicBoxContext().markOutputAsReadyToSend(0, m_previousTime, m_currentChunkEndDate);
|
||||
}
|
||||
|
||||
m_previousTime = m_currentChunkEndDate;
|
||||
|
||||
if (m_endState == EEndState::StimulationSent)
|
||||
{
|
||||
m_encoder.encodeEnd();
|
||||
this->getDynamicBoxContext().markOutputAsReadyToSend(0, m_previousTime, m_previousTime);
|
||||
m_endState = EEndState::Finished;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
class CBoxAlgorithmStreamEndDetector final : public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
static CIdentifier inputEBMLId() { return CIdentifier(0x0, 0x1); }
|
||||
static CIdentifier outputStimulationsID() { return CIdentifier(0x1, 0x1); }
|
||||
static CIdentifier settingStimulationNameID() { return CIdentifier(0x2, 0x1); }
|
||||
void release() override { delete this; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processInput(const size_t index) override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_StreamEndDetector)
|
||||
|
||||
protected:
|
||||
|
||||
Toolkit::TStreamStructureDecoder<CBoxAlgorithmStreamEndDetector> m_decoder;
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmStreamEndDetector> m_encoder;
|
||||
|
||||
uint64_t m_stimulationID = 0;
|
||||
uint64_t m_actionID = 0;
|
||||
|
||||
private:
|
||||
enum class EEndState
|
||||
{
|
||||
WaitingForEnd,
|
||||
EndReceived,
|
||||
StimulationSent,
|
||||
Finished
|
||||
};
|
||||
|
||||
uint64_t m_endDate = 0;
|
||||
uint64_t m_currentChunkEndDate = 0;
|
||||
uint64_t m_previousTime = 0;
|
||||
size_t m_inputEBMLIdx = 0;
|
||||
size_t m_outputStimulationsIdx = 0;
|
||||
bool m_isHeaderSent = false;
|
||||
EEndState m_endState = EEndState::WaitingForEnd;
|
||||
};
|
||||
|
||||
class CBoxAlgorithmStreamEndDetectorDesc final : public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
void release() override { }
|
||||
CString getName() const override { return CString("Stream End Detector"); }
|
||||
CString getAuthorName() const override { return CString("Jozef Legeny"); }
|
||||
CString getAuthorCompanyName() const override { return CString("Mensia Technologies"); }
|
||||
CString getShortDescription() const override { return CString("Sends a stimulation upon receiving an End chunk"); }
|
||||
CString getDetailedDescription() const override { return CString("Sends a stimulation upon receiving an End chunk"); }
|
||||
CString getCategory() const override { return CString("Stimulation"); }
|
||||
CString getVersion() const override { return CString("1.0"); }
|
||||
CString getSoftwareComponent() const override { return CString("openvibe-sdk"); }
|
||||
CString getAddedSoftwareVersion() const override { return CString("2.0.0"); }
|
||||
CString getUpdatedSoftwareVersion() const override { return CString("0.0.0"); }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_StreamEndDetector; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmStreamEndDetector; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("EBML Stream", OV_TypeId_EBMLStream, CBoxAlgorithmStreamEndDetector::inputEBMLId());
|
||||
prototype.addOutput("Output Stimulations", OV_TypeId_Stimulations, CBoxAlgorithmStreamEndDetector::outputStimulationsID());
|
||||
prototype.addSetting("Stimulation name", OV_TypeId_Stimulation, "OVTK_StimulationId_Label_00", false,
|
||||
CBoxAlgorithmStreamEndDetector::settingStimulationNameID());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_StreamEndDetectorDesc)
|
||||
};
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#include "ovpCBoxAlgorithmTimeout.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
bool CBoxAlgorithmTimeout::initialize()
|
||||
{
|
||||
m_timeoutState = ETimeoutState::No;
|
||||
|
||||
m_encoder.initialize(*this, 0);
|
||||
|
||||
const double timeout = double(FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 0));
|
||||
OV_ERROR_UNLESS_KRF(timeout > 0, "Timeout delay value must be positive and non-zero", Kernel::ErrorType::BadSetting);
|
||||
OV_ERROR_UNLESS_KRF(timeout == std::floor(timeout), "Timeout delay value is not an integer", Kernel::ErrorType::BadSetting);
|
||||
|
||||
m_timeout = uint64_t(timeout) << 32;
|
||||
m_stimulationToSend = FSettingValueAutoCast(*this->getBoxAlgorithmContext(), 1);
|
||||
|
||||
m_lastTimePolled = 0;
|
||||
m_previousTime = 0;
|
||||
m_isHeaderSent = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
/*******************************************************************************/
|
||||
|
||||
bool CBoxAlgorithmTimeout::uninitialize()
|
||||
{
|
||||
m_encoder.uninitialize();
|
||||
|
||||
return true;
|
||||
}
|
||||
/*******************************************************************************/
|
||||
|
||||
bool CBoxAlgorithmTimeout::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
// if there was nothing received on the input for a period of time we raise the
|
||||
// timeout flag and let the box send a stimulation
|
||||
if (m_timeoutState == ETimeoutState::No && getPlayerContext().getCurrentTime() > m_lastTimePolled + m_timeout)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "Timeout reached at time " << CTime(this->getPlayerContext().getCurrentTime()) << "\n";
|
||||
m_timeoutState = ETimeoutState::Occurred;
|
||||
}
|
||||
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
|
||||
return true;
|
||||
}
|
||||
/*******************************************************************************/
|
||||
|
||||
uint64_t CBoxAlgorithmTimeout::getClockFrequency() { return 16LL << 32; } // the box clock frequency
|
||||
/*******************************************************************************/
|
||||
|
||||
bool CBoxAlgorithmTimeout::processInput(const size_t /*index*/)
|
||||
{
|
||||
this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
|
||||
// every time we receive input we store the last kernel time
|
||||
m_lastTimePolled = this->getPlayerContext().getCurrentTime();
|
||||
|
||||
return true;
|
||||
}
|
||||
/*******************************************************************************/
|
||||
|
||||
bool CBoxAlgorithmTimeout::process()
|
||||
{
|
||||
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
|
||||
|
||||
// Discard input data
|
||||
for (size_t i = 0; i < boxCtx.getInputChunkCount(0); ++i) { boxCtx.markInputAsDeprecated(0, i); }
|
||||
|
||||
// Encoding the header
|
||||
if (!m_isHeaderSent)
|
||||
{
|
||||
m_encoder.encodeHeader();
|
||||
this->getDynamicBoxContext().markOutputAsReadyToSend(0, 0, 0);
|
||||
m_isHeaderSent = true;
|
||||
}
|
||||
|
||||
IStimulationSet* stimSet = m_encoder.getInputStimulationSet();
|
||||
stimSet->clear();
|
||||
|
||||
const uint64_t date = this->getPlayerContext().getCurrentTime();
|
||||
|
||||
// If the timeout is reached we send the stimulation on the output 0
|
||||
if (m_timeoutState == ETimeoutState::Occurred)
|
||||
{
|
||||
stimSet->appendStimulation(m_stimulationToSend, date, 0);
|
||||
m_timeoutState = ETimeoutState::Sent;
|
||||
}
|
||||
|
||||
// we need to send an empty chunk even if there's no stim
|
||||
m_encoder.encodeBuffer();
|
||||
this->getDynamicBoxContext().markOutputAsReadyToSend(0, m_previousTime, date);
|
||||
|
||||
m_previousTime = date;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include "../ovp_defines.h"
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
/**
|
||||
* \class CBoxAlgorithmTimeout
|
||||
* \author Jozef Legény (Inria)
|
||||
* \date Thu Mar 21 14:40:23 2013
|
||||
* \brief The class CBoxAlgorithmTimeout describes the box Timeout.
|
||||
*
|
||||
*/
|
||||
class CBoxAlgorithmTimeout final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
bool processInput(const size_t index) override;
|
||||
uint64_t getClockFrequency() override;
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, OVP_ClassId_BoxAlgorithm_Timeout)
|
||||
|
||||
protected:
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmTimeout> m_encoder;
|
||||
|
||||
private:
|
||||
enum class ETimeoutState { No, Occurred, Sent };
|
||||
|
||||
ETimeoutState m_timeoutState = ETimeoutState::No;
|
||||
bool m_isHeaderSent = false;
|
||||
|
||||
uint64_t m_timeout = 0;
|
||||
uint64_t m_lastTimePolled = 0;
|
||||
uint64_t m_previousTime = 0;
|
||||
uint64_t m_stimulationToSend = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class CBoxAlgorithmTimeoutDesc
|
||||
* \author Jozef Legény (Inria)
|
||||
* \date Thu Mar 21 14:40:23 2013
|
||||
* \brief Descriptor of the box Timeout.
|
||||
*
|
||||
*/
|
||||
class CBoxAlgorithmTimeoutDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
void release() override { }
|
||||
CString getName() const override { return "Timeout"; }
|
||||
CString getAuthorName() const override { return "Jozef Legény"; }
|
||||
CString getAuthorCompanyName() const override { return "Inria"; }
|
||||
CString getShortDescription() const override { return "Sends a stimulation after a period of time without receiving signal"; }
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return "Sends a stimulation after a period of time without receiving signal. Useful for stopping scenarios after hardware disconnection.";
|
||||
}
|
||||
|
||||
CString getCategory() const override { return "Stimulation"; }
|
||||
CString getVersion() const override { return "1.1"; }
|
||||
CString getSoftwareComponent() const override { return "openvibe-sdk"; }
|
||||
CString getAddedSoftwareVersion() const override { return "0.0.0"; }
|
||||
CString getUpdatedSoftwareVersion() const override { return "0.0.0"; }
|
||||
CIdentifier getCreatedClass() const override { return OVP_ClassId_BoxAlgorithm_Timeout; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmTimeout; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input Stream",OV_TypeId_StreamedMatrix);
|
||||
|
||||
prototype.addOutput("Output Stimulations",OV_TypeId_Stimulations);
|
||||
|
||||
prototype.addSetting("Timeout delay",OV_TypeId_Integer, "5");
|
||||
prototype.addSetting("Output Stimulation",OV_TypeId_Stimulation, "OVTK_StimulationId_Label_00");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_TimeoutDesc)
|
||||
};
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
// Boxes
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVP_ClassId_BoxAlgorithm_ClockStimulator OpenViBE::CIdentifier(0x4F756D3F, 0x29FF0B96)
|
||||
#define OVP_ClassId_BoxAlgorithm_ClockStimulatorDesc OpenViBE::CIdentifier(0x4FD067E9, 0x740D2AF0)
|
||||
#define OVP_ClassId_BoxAlgorithm_PlayerController OpenViBE::CIdentifier(0x5F426DCE, 0x08456E13)
|
||||
#define OVP_ClassId_BoxAlgorithm_PlayerControllerDesc OpenViBE::CIdentifier(0x2E4142D7, 0x3F957E25)
|
||||
#define OVP_ClassId_BoxAlgorithm_StimulationMultiplexer OpenViBE::CIdentifier(0x07DB4EFA, 0x472B0938)
|
||||
#define OVP_ClassId_BoxAlgorithm_StimulationMultiplexerDesc OpenViBE::CIdentifier(0x79EF4E4D, 0x178F09E6)
|
||||
#define OVP_ClassId_BoxAlgorithm_StimulationVoter OpenViBE::CIdentifier(0x2BBD61FC, 0x041A4EDB)
|
||||
#define OVP_ClassId_BoxAlgorithm_StimulationVoterDesc OpenViBE::CIdentifier(0x1C36287C, 0x6F143FBF)
|
||||
#define OVP_ClassId_BoxAlgorithm_StreamEndDetector OpenViBE::CIdentifier(0x44F2725A, 0x8E922233)
|
||||
#define OVP_ClassId_BoxAlgorithm_StreamEndDetectorDesc OpenViBE::CIdentifier(0x6DD8B6EA, 0xC581B3FC)
|
||||
#define OVP_ClassId_BoxAlgorithm_Timeout OpenViBE::CIdentifier(0x24FCD292, 0x5C8F6AA8)
|
||||
#define OVP_ClassId_BoxAlgorithm_TimeoutDesc OpenViBE::CIdentifier(0xB3D90844, 0x79A4CF6D)
|
||||
|
||||
// Type definitions
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define OVP_TypeId_Voting_ClearVotes OpenViBE::CIdentifier(0x17AE30F8, 0x40B57661)
|
||||
#define OVP_TypeId_Voting_ClearVotes_AfterOutput OpenViBE::CIdentifier(0x7FA81A20, 0x484023F9)
|
||||
#define OVP_TypeId_Voting_ClearVotes_WhenExpires OpenViBE::CIdentifier(0x02766639, 0x00B155B4)
|
||||
#define OVP_TypeId_Voting_OutputTime OpenViBE::CIdentifier(0x48583E8F, 0x47F22462)
|
||||
#define OVP_TypeId_Voting_OutputTime_Vote OpenViBE::CIdentifier(0x2F37507F, 0x00C06761)
|
||||
#define OVP_TypeId_Voting_OutputTime_Winner OpenViBE::CIdentifier(0x72416689, 0x17673658)
|
||||
#define OVP_TypeId_Voting_OutputTime_Last OpenViBE::CIdentifier(0x4F2830DB, 0x716C2930)
|
||||
#define OVP_TypeId_Voting_RejectClass_CanWin OpenViBE::CIdentifier(0x442F2F14, 0x7A17336C)
|
||||
#define OVP_TypeId_Voting_RejectClass_CanWin_Yes OpenViBE::CIdentifier(0x40011974, 0x54BB3C71)
|
||||
#define OVP_TypeId_Voting_RejectClass_CanWin_No OpenViBE::CIdentifier(0x275B746A, 0x480B302C)
|
||||
|
||||
#define OV_TypeId_PlayerAction OpenViBE::CIdentifier(0xCC14D8D6, 0xF27ECB73)
|
||||
#define OV_TypeId_PlayerAction_Play OpenViBE::CIdentifier(0x6BD7E1B3, 0x85E75066)
|
||||
#define OV_TypeId_PlayerAction_Stop OpenViBE::CIdentifier(0x8A72885E, 0xD537A9A4)
|
||||
#define OV_TypeId_PlayerAction_Pause OpenViBE::CIdentifier(0xD2FA4573, 0xE7F1D11D)
|
||||
#define OV_TypeId_PlayerAction_Forward OpenViBE::CIdentifier(0xE43E9888, 0x33A361ED)
|
||||
|
||||
// Global defines
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#ifdef TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
|
||||
#include "ovp_global_defines.h"
|
||||
#endif // TARGET_HAS_ThirdPartyOpenViBEPluginsGlobalDefines
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "ovp_defines.h"
|
||||
|
||||
#include "box-algorithms/ovpCBoxAlgorithmClockStimulator.h"
|
||||
#include "box-algorithms/ovpCBoxAlgorithmPlayerController.h"
|
||||
|
||||
#include "box-algorithms/ovpCBoxAlgorithmStimulationMultiplexer.h"
|
||||
#include "box-algorithms/ovpCBoxAlgorithmStimulationVoter.h"
|
||||
|
||||
#include "box-algorithms/ovpCBoxAlgorithmStreamEndDetector.h"
|
||||
#include "box-algorithms/ovpCBoxAlgorithmTimeout.h"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Stimulation {
|
||||
|
||||
OVP_Declare_Begin()
|
||||
context.getTypeManager().registerEnumerationType(OV_TypeId_PlayerAction, "Player Action");
|
||||
context.getTypeManager().registerEnumerationEntry(OV_TypeId_PlayerAction, "Play", OV_TypeId_PlayerAction_Play.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OV_TypeId_PlayerAction, "Stop", OV_TypeId_PlayerAction_Stop.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OV_TypeId_PlayerAction, "Pause", OV_TypeId_PlayerAction_Pause.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OV_TypeId_PlayerAction, "Forward", OV_TypeId_PlayerAction_Forward.id());
|
||||
|
||||
OVP_Declare_New(CBoxAlgorithmClockStimulatorDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmPlayerControllerDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmStimulationMultiplexerDesc);
|
||||
|
||||
OVP_Declare_New(CBoxAlgorithmStreamEndDetectorDesc);
|
||||
OVP_Declare_New(CBoxAlgorithmTimeoutDesc);
|
||||
|
||||
OVP_Declare_New(CBoxAlgorithmStimulationVoterDesc);
|
||||
context.getTypeManager().registerEnumerationType(OVP_TypeId_Voting_ClearVotes, "Clear votes");
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_ClearVotes, "When expires", OVP_TypeId_Voting_ClearVotes_WhenExpires.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_ClearVotes, "After output", OVP_TypeId_Voting_ClearVotes_AfterOutput.id());
|
||||
context.getTypeManager().registerEnumerationType(OVP_TypeId_Voting_OutputTime, "Output time");
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_OutputTime, "Time of voting", OVP_TypeId_Voting_OutputTime_Vote.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_OutputTime, "Time of last winning stimulus", OVP_TypeId_Voting_OutputTime_Winner.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_OutputTime, "Time of last voting stimulus", OVP_TypeId_Voting_OutputTime_Last.id());
|
||||
context.getTypeManager().registerEnumerationType(OVP_TypeId_Voting_RejectClass_CanWin, "Reject can win");
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_RejectClass_CanWin, "Yes", OVP_TypeId_Voting_RejectClass_CanWin_Yes.id());
|
||||
context.getTypeManager().registerEnumerationEntry(OVP_TypeId_Voting_RejectClass_CanWin, "No", OVP_TypeId_Voting_RejectClass_CanWin_No.id());
|
||||
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace Stimulation
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
Reference in New Issue
Block a user