init
This commit is contained in:
+232
@@ -0,0 +1,232 @@
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "CBoxAlgorithmHelloBidirectionnalGame.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloBidirectionnalGame::initialize()
|
||||
{
|
||||
//---------- Initialize Input/Output ----------
|
||||
m_signalDecoder.initialize(*this, 0);
|
||||
m_stimDecoder.initialize(*this, 1);
|
||||
m_iMatrix = m_signalDecoder.getOutputMatrix();
|
||||
m_iStimSet = m_stimDecoder.getOutputStimulationSet();
|
||||
|
||||
m_signalEncoder.initialize(*this, 0);
|
||||
m_stimEncoder.initialize(*this, 1);
|
||||
m_oMatrix = m_signalEncoder.getInputMatrix();
|
||||
m_oStimSet = m_stimEncoder.getInputStimulationSet();
|
||||
|
||||
//---------- Initialize LSL Stream (to Unity) ----------
|
||||
// These are supposed to be unique, so we don't have them in the box config
|
||||
m_outSignalID = CIdentifier::random().str();
|
||||
m_outMarkerID = CIdentifier::random().str();
|
||||
|
||||
while (m_outMarkerID == m_outSignalID) { m_outMarkerID = CIdentifier::random().str(); } // very unlikely
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "We Will create signal stream [" << m_outSignalName << ", id " << m_outSignalID
|
||||
<< "] and stimulation stream [" << m_outMarkerName << ", id " << m_outMarkerID << "]\n";
|
||||
|
||||
//---------- Create Headers for Output ----------
|
||||
// Matrix Header
|
||||
m_oMatrix->resize(1, 1);
|
||||
m_signalEncoder.encodeHeader();
|
||||
|
||||
// Stimulation Header
|
||||
m_oStimSet->setStimulationCount(0); // reset stimulation output
|
||||
m_stimEncoder.encodeHeader();
|
||||
|
||||
Kernel::IBoxIO& boxCtx = this->getDynamicBoxContext();
|
||||
boxCtx.markOutputAsReadyToSend(0, m_lastMatrixTime, m_lastMatrixTime); // Makes the output available
|
||||
boxCtx.markOutputAsReadyToSend(1, m_lastStimTime, m_lastStimTime); // Makes the output available
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloBidirectionnalGame::uninitialize()
|
||||
{
|
||||
//---------- Uninitialize Input/Output ----------
|
||||
m_signalDecoder.uninitialize();
|
||||
m_stimDecoder.uninitialize();
|
||||
m_signalEncoder.uninitialize();
|
||||
m_stimEncoder.uninitialize();
|
||||
|
||||
//---------- Delete LSL Stream Inlet/Outlet ----------
|
||||
if (m_signalOutlet)
|
||||
{
|
||||
delete m_signalOutlet;
|
||||
m_signalOutlet = nullptr;
|
||||
}
|
||||
if (m_stimOutlet)
|
||||
{
|
||||
delete m_stimOutlet;
|
||||
m_stimOutlet = nullptr;
|
||||
}
|
||||
|
||||
if (m_signalInlet)
|
||||
{
|
||||
m_signalInlet->close_stream();
|
||||
delete m_signalInlet;
|
||||
m_signalInlet = nullptr;
|
||||
}
|
||||
|
||||
if (m_stimInlet)
|
||||
{
|
||||
m_stimInlet->close_stream();
|
||||
delete m_stimInlet;
|
||||
m_stimInlet = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloBidirectionnalGame::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloBidirectionnalGame::process()
|
||||
{
|
||||
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const uint64_t currentTime = getPlayerContext().getCurrentTime();
|
||||
|
||||
//---------- Emission Part ----------
|
||||
// Process signals
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
m_signalDecoder.decode(i);
|
||||
if (m_signalDecoder.isHeaderReceived() && !m_signalOutlet)
|
||||
{
|
||||
const size_t samplesPerBlock = m_signalDecoder.getOutputMatrix()->getDimensionSize(1);
|
||||
const size_t frequency = m_signalDecoder.getOutputSamplingRate();
|
||||
|
||||
lsl::stream_info signalInfo = createSignalStreamInfo(m_outSignalName, m_outSignalID, m_signalDecoder.getOutputMatrix(), frequency);
|
||||
// make a new outlet
|
||||
try { m_signalOutlet = new lsl::stream_outlet(signalInfo, int(samplesPerBlock)); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << "Unable to create signal outlet\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_signalDecoder.isBufferReceived())
|
||||
{
|
||||
sendSignal(m_signalOutlet, m_iMatrix, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
|
||||
}
|
||||
//if (m_signalDecoder.isEndReceived()) { }
|
||||
}
|
||||
|
||||
// Process stimuli -> LSL markers.
|
||||
// Note that stimuli with identifiers not fitting to int will be mangled by a static cast.
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
|
||||
{
|
||||
m_stimDecoder.decode(i);
|
||||
if (m_stimDecoder.isHeaderReceived() && !m_stimOutlet)
|
||||
{
|
||||
// Open a stimulus stream
|
||||
lsl::stream_info info = createStimulationStreamInfo(m_outMarkerName, m_outMarkerID);
|
||||
|
||||
try { m_stimOutlet = new lsl::stream_outlet(info); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << "Unable to create marker outlet\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_stimDecoder.isBufferReceived()) { sendStimulation(m_stimOutlet, m_iStimSet); }
|
||||
//if (m_stimDecoder.isEndReceived()) { }
|
||||
}
|
||||
|
||||
|
||||
//---------- Reception Part ----------
|
||||
if (!m_signalInlet) // We don't have a signal inlet
|
||||
{
|
||||
const lsl::stream_info signalInfo = findStreamInfo(m_inSignalName, "", 0); // timeout of 0 to avoid blocking OpenViBE
|
||||
if (signalInfo.name() == m_inSignalName)
|
||||
{
|
||||
m_signalInlet = new lsl::stream_inlet(signalInfo);
|
||||
try { m_signalInlet->open_stream(); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open signal stream with name [" << signalInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "We have open stream [" << signalInfo.name() << "]\n";
|
||||
}
|
||||
}
|
||||
if (m_signalInlet) // We have a signal inlet
|
||||
{
|
||||
double time;
|
||||
// Signal
|
||||
try { time = m_signalInlet->pull_sample(&m_bufferLSL, 1, 0.0); } // 2 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get signal sample\n";
|
||||
return false;
|
||||
}
|
||||
if (std::abs(time) > 0.0)
|
||||
{
|
||||
m_oMatrix->getBuffer()[0] = double(m_bufferLSL);
|
||||
m_signalEncoder.encodeBuffer(); // Buffer encoded
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, currentTime); // Makes the output available
|
||||
m_lastMatrixTime = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_stimInlet) // We haven't a stimulation inlet
|
||||
{
|
||||
const lsl::stream_info stimInfo = findStreamInfo(m_inMarkerName, "", 0); // timeout of 0 to avoid blocking OpenViBE
|
||||
if (stimInfo.name() == m_inMarkerName)
|
||||
{
|
||||
m_stimInlet = new lsl::stream_inlet(stimInfo);
|
||||
try { m_stimInlet->open_stream(); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open marker stream with name [" << stimInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "We have open stream [" << stimInfo.name() << "]\n";
|
||||
}
|
||||
}
|
||||
if (m_stimInlet) // We have a stimulation inlet
|
||||
{
|
||||
double time;
|
||||
try { time = m_stimInlet->pull_sample(&m_bufferLSL, 1, 0.0); } // 1 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get stimulation sample\n";
|
||||
return false;
|
||||
}
|
||||
if (std::abs(time) > 0.0)
|
||||
{
|
||||
m_oStimSet->setStimulationCount(0); // reset stimulation output
|
||||
m_oStimSet->appendStimulation(uint64_t(m_bufferLSL), currentTime, 0);
|
||||
m_stimEncoder.encodeBuffer(); // Buffer encoded
|
||||
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, currentTime); // Makes the output available
|
||||
m_lastStimTime = currentTime;
|
||||
this->getLogManager() << Kernel::LogLevel_Info << "Stim received with time " << time << "s in the unity app\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CBoxAlgorithmHelloBidirectionnalGame.hpp
|
||||
/// \brief Class of the box that communicates with Hello Bidirectionnal Game.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 24/02/2021
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "defines.hpp"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <lsl_cpp.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
/// <summary> The class CBoxAlgorithmHelloBidirectionnalGame describes the box that sends value in LSL. </summary>
|
||||
class CBoxAlgorithmHelloBidirectionnalGame final : virtual 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>, Game_Box_Hello_Bidirectionnal)
|
||||
|
||||
protected:
|
||||
|
||||
// Encoder / Decoder
|
||||
Toolkit::TStimulationDecoder<CBoxAlgorithmHelloBidirectionnalGame> m_stimDecoder;
|
||||
Toolkit::TSignalDecoder<CBoxAlgorithmHelloBidirectionnalGame> m_signalDecoder;
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmHelloBidirectionnalGame> m_stimEncoder;
|
||||
Toolkit::TSignalEncoder<CBoxAlgorithmHelloBidirectionnalGame> m_signalEncoder;
|
||||
|
||||
// Input/ Output
|
||||
CMatrix *m_iMatrix = nullptr, *m_oMatrix = nullptr;
|
||||
IStimulationSet *m_iStimSet = nullptr, *m_oStimSet = nullptr;
|
||||
uint64_t m_lastMatrixTime = 0, m_lastStimTime = 0;
|
||||
|
||||
// LSL Stream
|
||||
lsl::stream_outlet *m_signalOutlet = nullptr, *m_stimOutlet = nullptr;
|
||||
lsl::stream_inlet *m_signalInlet = nullptr, *m_stimInlet = nullptr;
|
||||
const std::string m_outSignalName = "ovOutSignal", m_outMarkerName = "ovOutMarkers";
|
||||
const std::string m_inSignalName = "ovInSignal", m_inMarkerName = "ovInMarkers";
|
||||
std::string m_outSignalID, m_outMarkerID;
|
||||
float m_bufferLSL = 0.0;
|
||||
};
|
||||
|
||||
|
||||
/// <summary> Descriptor of the box Hello Bidirectionnal Game. </summary>
|
||||
class CBoxAlgorithmHelloBidirectionnalGameDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return "Hello Bidirectionnal Game"; }
|
||||
CString getAuthorName() const override { return "Thibaut Monseigne"; }
|
||||
CString getAuthorCompanyName() const override { return "Inria"; }
|
||||
CString getShortDescription() const override
|
||||
{
|
||||
return "Send input stream via LabStreamingLayer (LSL) to the unity game Hello Bidirectionnal and receive back matrix and stimulation.";
|
||||
}
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-bidirectionnal).\n";
|
||||
}
|
||||
CString getCategory() const override { return "Games"; }
|
||||
CString getVersion() const override { return "0.1"; }
|
||||
CString getStockItemName() const override { return "gtk-connect"; }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return Game_Box_Hello_Bidirectionnal; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmHelloBidirectionnalGame; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input signal", OV_TypeId_Signal);
|
||||
prototype.addInput("Input stimulations", OV_TypeId_Stimulations);
|
||||
prototype.addOutput("Output matrix", OV_TypeId_StreamedMatrix);
|
||||
prototype.addOutput("Output stimulations", OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_Bidirectionnal_Desc)
|
||||
};
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "CBoxAlgorithmHelloSenderGame.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloSenderGame::initialize()
|
||||
{
|
||||
m_signalInlet = nullptr;
|
||||
m_stimInlet = nullptr;
|
||||
|
||||
m_signalEncoder.initialize(*this, 0);
|
||||
m_stimEncoder.initialize(*this, 1);
|
||||
m_oMatrix = m_signalEncoder.getInputMatrix();
|
||||
m_oStimSet = m_stimEncoder.getInputStimulationSet();
|
||||
|
||||
// Signal Stream
|
||||
const lsl::stream_info signalInfo = findStreamInfo(m_signalName);
|
||||
if (signalInfo.name() != m_signalName)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Error getting signal stream info for [" << signalInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_signalInlet = new lsl::stream_inlet(signalInfo);
|
||||
if (!m_signalInlet)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Error getting signal inlet for [" << signalInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
try { m_signalInlet->open_stream(); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open signal stream with name [" << signalInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stimulation Stream
|
||||
const lsl::stream_info stimInfo = findStreamInfo(m_markerName);
|
||||
if (stimInfo.name() != m_markerName)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Error getting marker stream info for [" << stimInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
m_stimInlet = new lsl::stream_inlet(stimInfo);
|
||||
if (!m_stimInlet)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Error getting marker inlet for [" << stimInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
try { m_stimInlet->open_stream(); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to open marker stream with name [" << stimInfo.name() << "]\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloSenderGame::uninitialize()
|
||||
{
|
||||
m_signalEncoder.uninitialize();
|
||||
m_stimEncoder.uninitialize();
|
||||
|
||||
if (m_signalInlet)
|
||||
{
|
||||
m_signalInlet->close_stream();
|
||||
delete m_signalInlet;
|
||||
m_signalInlet = nullptr;
|
||||
}
|
||||
|
||||
if (m_stimInlet)
|
||||
{
|
||||
m_stimInlet->close_stream();
|
||||
delete m_stimInlet;
|
||||
m_stimInlet = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloSenderGame::processClock(Kernel::CMessageClock& /*msg*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloSenderGame::process()
|
||||
{
|
||||
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
const uint64_t currentTime = getPlayerContext().getCurrentTime();
|
||||
|
||||
// Header
|
||||
if (!m_headerSent)
|
||||
{
|
||||
m_buffer = new float[2];
|
||||
|
||||
// Matrix Header
|
||||
m_oMatrix->resize(2, 1);
|
||||
m_signalEncoder.encodeHeader();
|
||||
|
||||
// Stimulation Header
|
||||
m_oStimSet->setStimulationCount(0); // reset stimulation output
|
||||
m_stimEncoder.encodeHeader();
|
||||
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, m_lastMatrixTime); // Makes the output available
|
||||
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, m_lastStimTime); // Makes the output available
|
||||
m_headerSent = true;
|
||||
this->getLogManager() << Kernel::LogLevel_Info << "Header created\n";
|
||||
}
|
||||
|
||||
// Core
|
||||
double time;
|
||||
// Signal
|
||||
try { time = m_signalInlet->pull_sample(m_buffer, 2, 0.0); } // 2 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get signal sample\n";
|
||||
return false;
|
||||
}
|
||||
if (std::abs(time) > 0.0)
|
||||
{
|
||||
double* buffer = m_oMatrix->getBuffer();
|
||||
buffer[0] = double(m_buffer[0]);
|
||||
buffer[1] = double(m_buffer[1]);
|
||||
m_signalEncoder.encodeBuffer(); // Buffer encoded
|
||||
boxContext.markOutputAsReadyToSend(0, m_lastMatrixTime, currentTime); // Makes the output available
|
||||
m_lastMatrixTime = currentTime;
|
||||
}
|
||||
|
||||
// Stimulation
|
||||
try { time = m_stimInlet->pull_sample(m_buffer, 1, 0.0); } // 1 element timeout to 0.0 to avoid lag (OpenViBE can't have background task)
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << Kernel::LogLevel_Error << "Failed to get stimulation sample\n";
|
||||
return false;
|
||||
}
|
||||
if (std::abs(time) > 0.0)
|
||||
{
|
||||
m_oStimSet->setStimulationCount(0); // reset stimulation output
|
||||
m_oStimSet->appendStimulation(uint64_t(m_buffer[0]), currentTime, 0);
|
||||
m_stimEncoder.encodeBuffer(); // Buffer encoded
|
||||
boxContext.markOutputAsReadyToSend(1, m_lastStimTime, currentTime); // Makes the output available
|
||||
m_lastStimTime = currentTime;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CBoxAlgorithmHelloSenderGame.hpp
|
||||
/// \brief Class of the box that communicate with Hello Sender Game.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "defines.hpp"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <lsl_cpp.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
/// <summary> The class CBoxAlgorithmHelloSenderGame describes the box that send value in LSL. </summary>
|
||||
class CBoxAlgorithmHelloSenderGame final : virtual public Toolkit::TBoxAlgorithm<IBoxAlgorithm>
|
||||
{
|
||||
public:
|
||||
void release() override { delete this; }
|
||||
|
||||
uint64_t getClockFrequency() override { return 64LL << 32; }
|
||||
bool initialize() override;
|
||||
bool uninitialize() override;
|
||||
|
||||
bool processClock(Kernel::CMessageClock& msg) override;
|
||||
|
||||
bool process() override;
|
||||
|
||||
_IsDerivedFromClass_Final_(Toolkit::TBoxAlgorithm<IBoxAlgorithm>, Game_Box_Hello_Sender)
|
||||
|
||||
protected:
|
||||
|
||||
// Decoders
|
||||
Toolkit::TStimulationEncoder<CBoxAlgorithmHelloSenderGame> m_stimEncoder;
|
||||
Toolkit::TSignalEncoder<CBoxAlgorithmHelloSenderGame> m_signalEncoder;
|
||||
CMatrix* m_oMatrix = nullptr;
|
||||
IStimulationSet* m_oStimSet = nullptr;
|
||||
float* m_buffer = nullptr;
|
||||
bool m_headerSent = false;
|
||||
uint64_t m_lastMatrixTime = 0;
|
||||
uint64_t m_lastStimTime = 0;
|
||||
|
||||
lsl::stream_inlet *m_signalInlet = nullptr, *m_stimInlet = nullptr;
|
||||
const std::string m_signalName = "ovSignal", m_markerName = "ovMarker";
|
||||
};
|
||||
|
||||
|
||||
/// <summary> Descriptor of the box Hello Sender Game. </summary>
|
||||
class CBoxAlgorithmHelloSenderGameDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return "Hello Sender Game"; }
|
||||
CString getAuthorName() const override { return "Thibaut Monseigne"; }
|
||||
CString getAuthorCompanyName() const override { return "Inria"; }
|
||||
CString getShortDescription() const override { return "Receive stream via LabStreamingLayer (LSL) from the unity game Hello Sender."; }
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-sender).\n";
|
||||
}
|
||||
CString getCategory() const override { return "Games"; }
|
||||
CString getVersion() const override { return "0.1"; }
|
||||
CString getStockItemName() const override { return "gtk-connect"; }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return Game_Box_Hello_Sender; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmHelloSenderGame; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addOutput("Output matrix", OV_TypeId_StreamedMatrix);
|
||||
prototype.addOutput("Output stimulations", OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_Sender_Desc)
|
||||
};
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "CBoxAlgorithmHelloWorldGame.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloWorldGame::initialize()
|
||||
{
|
||||
m_signalOutlet = nullptr;
|
||||
m_stimOutlet = nullptr;
|
||||
|
||||
m_signalDecoder.initialize(*this, 0);
|
||||
m_stimDecoder.initialize(*this, 1);
|
||||
m_iMatrix = m_signalDecoder.getOutputMatrix();
|
||||
m_iStimSet = m_stimDecoder.getOutputStimulationSet();
|
||||
|
||||
// These are supposed to be unique, so we don't have them in the box config
|
||||
m_signalID = CIdentifier::random().str();
|
||||
m_markerID = CIdentifier::random().str();
|
||||
|
||||
while (m_markerID == m_signalID) { m_markerID = CIdentifier::random().str(); } // very unlikely
|
||||
|
||||
this->getLogManager() << Kernel::LogLevel_Trace << "We Will create streams [" << m_signalName << ", id " << m_signalID
|
||||
<< "] and [" << m_markerName << ", id " << m_markerID << "]\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloWorldGame::uninitialize()
|
||||
{
|
||||
m_signalDecoder.uninitialize();
|
||||
m_stimDecoder.uninitialize();
|
||||
|
||||
if (m_signalOutlet)
|
||||
{
|
||||
delete m_signalOutlet;
|
||||
m_signalOutlet = nullptr;
|
||||
}
|
||||
if (m_stimOutlet)
|
||||
{
|
||||
delete m_stimOutlet;
|
||||
m_stimOutlet = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloWorldGame::processInput(const size_t /*index*/)
|
||||
{
|
||||
getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
bool CBoxAlgorithmHelloWorldGame::process()
|
||||
{
|
||||
// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
|
||||
Kernel::IBoxIO& boxContext = this->getDynamicBoxContext();
|
||||
|
||||
// Process signals
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(0); ++i)
|
||||
{
|
||||
m_signalDecoder.decode(i);
|
||||
if (m_signalDecoder.isHeaderReceived() && !m_signalOutlet)
|
||||
{
|
||||
const size_t samplesPerBlock = m_signalDecoder.getOutputMatrix()->getDimensionSize(1);
|
||||
const size_t frequency = m_signalDecoder.getOutputSamplingRate();
|
||||
|
||||
lsl::stream_info signalInfo = createSignalStreamInfo(m_signalName, m_signalID, m_signalDecoder.getOutputMatrix(), frequency);
|
||||
// make a new outlet
|
||||
try { m_signalOutlet = new lsl::stream_outlet(signalInfo, int(samplesPerBlock)); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << "Unable to create signal outlet\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_signalDecoder.isBufferReceived())
|
||||
{
|
||||
sendSignal(m_signalOutlet, m_iMatrix, boxContext.getInputChunkStartTime(0, i), boxContext.getInputChunkEndTime(0, i));
|
||||
}
|
||||
//if (m_signalDecoder.isEndReceived()) { }
|
||||
}
|
||||
|
||||
// Process stimuli -> LSL markers.
|
||||
// Note that stimuli with identifiers not fitting to int will be mangled by a static cast.
|
||||
for (size_t i = 0; i < boxContext.getInputChunkCount(1); ++i)
|
||||
{
|
||||
m_stimDecoder.decode(i);
|
||||
if (m_stimDecoder.isHeaderReceived() && !m_stimOutlet)
|
||||
{
|
||||
// Open a stimulus stream
|
||||
lsl::stream_info info = createStimulationStreamInfo(m_markerName, m_markerID);
|
||||
|
||||
try { m_stimOutlet = new lsl::stream_outlet(info); }
|
||||
catch (...)
|
||||
{
|
||||
this->getLogManager() << "Unable to create marker outlet\n";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (m_stimDecoder.isBufferReceived()) { sendStimulation(m_stimOutlet, m_iStimSet); }
|
||||
//if (m_stimDecoder.isEndReceived()) { }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file CBoxAlgorithmHelloWorldGame.hpp
|
||||
/// \brief Class of the box that communicate with Hello World Game.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "defines.hpp"
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <toolkit/ovtk_all.h>
|
||||
|
||||
#include <lsl_cpp.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
/// <summary> The class CBoxAlgorithmHelloWorldGame describes the box that send value in LSL. </summary>
|
||||
class CBoxAlgorithmHelloWorldGame final : virtual 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>, Game_Box_Hello_World)
|
||||
|
||||
protected:
|
||||
|
||||
// Decoders
|
||||
Toolkit::TStimulationDecoder<CBoxAlgorithmHelloWorldGame> m_stimDecoder;
|
||||
Toolkit::TSignalDecoder<CBoxAlgorithmHelloWorldGame> m_signalDecoder;
|
||||
CMatrix* m_iMatrix = nullptr;
|
||||
IStimulationSet* m_iStimSet = nullptr;
|
||||
|
||||
lsl::stream_outlet *m_signalOutlet = nullptr, *m_stimOutlet = nullptr;
|
||||
const std::string m_signalName = "ovSignal", m_markerName = "ovMarkers";
|
||||
std::string m_signalID, m_markerID;
|
||||
};
|
||||
|
||||
|
||||
/// <summary> Descriptor of the box Hello World Game. </summary>
|
||||
class CBoxAlgorithmHelloWorldGameDesc final : virtual public IBoxAlgorithmDesc
|
||||
{
|
||||
public:
|
||||
|
||||
void release() override { }
|
||||
|
||||
CString getName() const override { return "Hello World Game"; }
|
||||
CString getAuthorName() const override { return "Thibaut Monseigne"; }
|
||||
CString getAuthorCompanyName() const override { return "Inria"; }
|
||||
CString getShortDescription() const override { return "Send input stream via LabStreamingLayer (LSL) to the unity game Hello World."; }
|
||||
CString getDetailedDescription() const override
|
||||
{
|
||||
return "The Unity Game is in the OpenViBE Unity Game Set of Repository (https://gitlab.inria.fr/openvibe/unity-games/hello-world).\n";
|
||||
}
|
||||
CString getCategory() const override { return "Games"; }
|
||||
CString getVersion() const override { return "0.1"; }
|
||||
CString getStockItemName() const override { return "gtk-connect"; }
|
||||
|
||||
CIdentifier getCreatedClass() const override { return Game_Box_Hello_World; }
|
||||
IPluginObject* create() override { return new CBoxAlgorithmHelloWorldGame; }
|
||||
|
||||
bool getBoxPrototype(Kernel::IBoxProto& prototype) const override
|
||||
{
|
||||
prototype.addInput("Input signal", OV_TypeId_Signal);
|
||||
prototype.addInput("Input stimulations", OV_TypeId_Stimulations);
|
||||
return true;
|
||||
}
|
||||
|
||||
_IsDerivedFromClass_Final_(IBoxAlgorithmDesc, Game_Box_Hello_World_Desc)
|
||||
};
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
@@ -0,0 +1,21 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file defines.hpp
|
||||
/// \brief Defines list for Setting, Shortcut Macro and const.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
// Boxes
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
#define Game_Box_Hello_World OpenViBE::CIdentifier(0x46705bc3, 0x3058a939)
|
||||
#define Game_Box_Hello_World_Desc OpenViBE::CIdentifier(0x3f921b93, 0xadb2b2ec)
|
||||
#define Game_Box_Hello_Sender OpenViBE::CIdentifier(0x4cbf4237, 0x24f54a7c)
|
||||
#define Game_Box_Hello_Sender_Desc OpenViBE::CIdentifier(0x5730a8f1, 0x96a608cc)
|
||||
#define Game_Box_Hello_Bidirectionnal OpenViBE::CIdentifier(0x47616d65, 0x42696469)
|
||||
#define Game_Box_Hello_Bidirectionnal_Desc OpenViBE::CIdentifier(0x47616d65, 0x42696464)
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <openvibe/ov_all.h>
|
||||
//#include "defines.hpp"
|
||||
|
||||
// Boxes Includes
|
||||
#include "boxes/CBoxAlgorithmHelloWorldGame.hpp"
|
||||
#include "boxes/CBoxAlgorithmHelloSenderGame.hpp"
|
||||
#include "boxes/CBoxAlgorithmHelloBidirectionnalGame.hpp"
|
||||
|
||||
namespace OpenViBE {
|
||||
namespace Plugins {
|
||||
namespace Games {
|
||||
|
||||
OVP_Declare_Begin()
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
// Register boxes
|
||||
OVP_Declare_New(CBoxAlgorithmHelloWorldGameDesc)
|
||||
OVP_Declare_New(CBoxAlgorithmHelloSenderGameDesc)
|
||||
OVP_Declare_New(CBoxAlgorithmHelloBidirectionnalGameDesc)
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
OVP_Declare_End()
|
||||
|
||||
} // namespace Games
|
||||
} // namespace Plugins
|
||||
} // namespace OpenViBE
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <iostream>
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
lsl::stream_info createSignalStreamInfo(const std::string& name, const std::string& id, const OpenViBE::CMatrix* matrix, const size_t frequency)
|
||||
{
|
||||
const size_t nChannel = matrix->getDimensionSize(0);
|
||||
|
||||
// Open a signal stream
|
||||
lsl::stream_info res(name, "signal", int(nChannel), double(frequency), lsl::cf_float32, id);
|
||||
|
||||
lsl::xml_element channels = res.desc().append_child("channels");
|
||||
for (size_t c = 0; c < nChannel; ++c)
|
||||
{
|
||||
const std::string tmp = matrix->getDimensionLabel(0, c);
|
||||
channels.append_child("channel").append_child_value("label", tmp).append_child_value("unit", "unknown").append_child_value("type", "signal");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
lsl::stream_info createStimulationStreamInfo(const std::string& name, const std::string& id)
|
||||
{
|
||||
lsl::stream_info res(name, "Markers", 1, lsl::IRREGULAR_RATE, lsl::cf_int32, id);
|
||||
res.desc().append_child("channels").append_child("channel").append_child_value("label", "Stimulations").append_child_value("type", "marker");
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void sendSignal(lsl::stream_outlet* outlet, const OpenViBE::CMatrix* matrix, const uint64_t startTime, const uint64_t endTime)
|
||||
{
|
||||
if (outlet->have_consumers())
|
||||
{
|
||||
const size_t nChannel = matrix->getDimensionSize(0);
|
||||
const size_t nSamples = matrix->getDimensionSize(1);
|
||||
const double* iBuffer = matrix->getBuffer();
|
||||
std::vector<float> buffer(nChannel);
|
||||
|
||||
// note: the step computed below should be exactly the same as could be obtained from the sampling rate
|
||||
const double start = OpenViBE::CTime(startTime).toSeconds();
|
||||
const double step = OpenViBE::CTime(endTime - startTime).toSeconds() / double(nSamples);
|
||||
|
||||
for (size_t s = 0; s < nSamples; ++s)
|
||||
{
|
||||
for (size_t c = 0; c < nChannel; ++c) { buffer[c] = float(iBuffer[c * nSamples + s]); }
|
||||
outlet->push_sample(buffer, start + double(s) * step);
|
||||
}
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
void sendStimulation(lsl::stream_outlet* outlet, const OpenViBE::IStimulationSet* stimSet)
|
||||
{
|
||||
if (outlet->have_consumers())
|
||||
{
|
||||
for (size_t s = 0; s < stimSet->getStimulationCount(); ++s)
|
||||
{
|
||||
const int code = int(stimSet->getStimulationIdentifier(s));
|
||||
const double date = OpenViBE::CTime(stimSet->getStimulationDate(s)).toSeconds();
|
||||
|
||||
outlet->push_sample(&code, date);
|
||||
}
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
lsl::stream_info findStreamInfo(const std::string& name, const std::string& id, const int timeout)
|
||||
{
|
||||
// Find the signal stream
|
||||
const std::vector<lsl::stream_info> infos = lsl::resolve_stream("name", name, 1, timeout);
|
||||
if (infos.empty())
|
||||
{
|
||||
if (timeout != 0) { std::cerr << "Failed to find stream with name [" << name << "]\n"; } // Avoid a print if timeout is 0
|
||||
return lsl::stream_info();
|
||||
}
|
||||
|
||||
for (const auto& i : infos)
|
||||
{
|
||||
if (i.source_id() == id) { return i; } // This is the best one
|
||||
}
|
||||
return infos[0];
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
@@ -0,0 +1,62 @@
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
///
|
||||
/// \file utils.hpp
|
||||
/// \brief Defines some function to facilitate Box Management.
|
||||
/// \author Thibaut Monseigne (Inria).
|
||||
/// \version 1.0.
|
||||
/// \date 12/03/2020.
|
||||
/// \copyright <a href="https://choosealicense.com/licenses/agpl-3.0/">GNU Affero General Public License v3.0</a>.
|
||||
///
|
||||
///-------------------------------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef TARGET_HAS_ThirdPartyLSL
|
||||
|
||||
#include <openvibe/ov_all.h>
|
||||
#include <lsl_cpp.h>
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Sending
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary> Create the stream information for signals.</summary>
|
||||
/// <param name="name"> The name of the stream. </param>
|
||||
/// <param name="id"> The identifier of the stream. </param>
|
||||
/// <param name="matrix"> The matrix to get infos (channel number and label).</param>
|
||||
/// <param name="frequency"> The signal frequency.</param>
|
||||
/// <returns> the stream info. </returns>
|
||||
lsl::stream_info createSignalStreamInfo(const std::string& name, const std::string& id, const OpenViBE::CMatrix* matrix, const size_t frequency);
|
||||
|
||||
/// <summary> Create the stream information for stimulations.</summary>
|
||||
/// <param name="name"> The name of the stream. </param>
|
||||
/// <param name="id"> The identifier of the stream. </param>
|
||||
/// <returns> the stream info. </returns>
|
||||
lsl::stream_info createStimulationStreamInfo(const std::string& name, const std::string& id);
|
||||
|
||||
/// <summary> Send Signal in LSL outlet. </summary>
|
||||
/// <param name="outlet"> The LSL outlet. </param>
|
||||
/// <param name="matrix"> The matrix with the signal to send. </param>
|
||||
/// <param name="startTime"> The start time of the signal. </param>
|
||||
/// <param name="endTime"> The end time of the signal. </param>
|
||||
void sendSignal(lsl::stream_outlet* outlet, const OpenViBE::CMatrix* matrix, const uint64_t startTime, const uint64_t endTime);
|
||||
|
||||
/// <summary> Send the stimulation in LSL outlet. </summary>
|
||||
/// <param name="outlet"> The LSL outlet. </param>
|
||||
/// <param name="stimSet">The stimulation set to send. </param>
|
||||
void sendStimulation(lsl::stream_outlet* outlet, const OpenViBE::IStimulationSet* stimSet);
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Receiving
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary> Finds the stream information with the function <c>lsl::resolve_stream</c>. </summary>
|
||||
/// <param name="name"> The expected name of the stream. </param>
|
||||
/// <param name="id"> Optionally The expected ID of the stream in addition of the name. </param>
|
||||
/// <param name="timeout"> Optionally a timeout of the operation, in seconds (default: no timeout).
|
||||
/// If the timeout expires, a default stream info is returned. </param>
|
||||
/// <returns></returns>
|
||||
lsl::stream_info findStreamInfo(const std::string& name, const std::string& id = "", const int timeout = LSL_FOREVER);
|
||||
|
||||
#endif // TARGET_HAS_ThirdPartyLSL
|
||||
Reference in New Issue
Block a user