You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ovasCPluginLSLOutput.cpp 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #if defined TARGET_HAS_ThirdPartyLSL
  2. /*
  3. * Notes: This code should be kept compatible with changes to LSL Input Driver in OpenViBE Acquisition Server,
  4. * and LSL Export box in Designer.
  5. *
  6. */
  7. #include "ovasCPluginLSLOutput.h"
  8. #include <vector>
  9. #include <system/ovCTime.h>
  10. #include <labstreamlayer/Utils.hpp>
  11. namespace OpenViBE {
  12. namespace AcquisitionServer {
  13. namespace Plugins {
  14. CPluginLSLOutput::CPluginLSLOutput(const Kernel::IKernelContext& ctx)
  15. : IAcquisitionServerPlugin(ctx, CString("AcquisitionServer_Plugin_LabStreamingLayerOutput"))
  16. {
  17. m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Loading plugin: LSL Output\n";
  18. m_settings.add("LSL_EnableLSLOutput", &m_IsLSLOutputEnabled);
  19. m_settings.add("LSL_SignalStreamName", &m_SignalStreamName);
  20. m_settings.add("LSL_MarkerStreamName", &m_MarkerStreamName);
  21. m_settings.load();
  22. // These are not saved or loaded from .conf as they are supposed to be unique
  23. m_SignalStreamID = CIdentifier::random().str();
  24. m_MarkerStreamID = CIdentifier::random().str();
  25. while (m_MarkerStreamID == m_SignalStreamID) { m_MarkerStreamID = CIdentifier::random().str(); } // very unlikely
  26. }
  27. CPluginLSLOutput::~CPluginLSLOutput()
  28. {
  29. if (m_signalOutlet)
  30. {
  31. delete m_signalOutlet;
  32. m_signalOutlet = nullptr;
  33. }
  34. if (m_stimulusOutlet)
  35. {
  36. delete m_stimulusOutlet;
  37. m_stimulusOutlet = nullptr;
  38. }
  39. }
  40. // Hooks
  41. bool CPluginLSLOutput::startHook(const std::vector<CString>& selectedChannelNames, const size_t sampling, const size_t nChannel,
  42. const size_t nSamplePerSentBlock)
  43. {
  44. m_nSamplePerSentBlock = nSamplePerSentBlock;
  45. m_useOVTimestamps = m_kernelCtx.getConfigurationManager().expandAsBoolean("${LSL_UseOVTimestamps}", m_useOVTimestamps);
  46. m_startTime = System::Time::zgetTime();
  47. if (m_IsLSLOutputEnabled)
  48. {
  49. m_kernelCtx.getLogManager() << Kernel::LogLevel_Trace << "Will create streams [" << m_SignalStreamName << ", id " << m_SignalStreamID << "] and ["
  50. << m_MarkerStreamName << ", id " << m_MarkerStreamID << "]\n";
  51. // Open a signal stream
  52. lsl::stream_info signalInfo(m_SignalStreamName, "signal", int(nChannel), double(sampling), lsl::cf_float32, m_SignalStreamID);
  53. lsl::xml_element channels = signalInfo.desc().append_child("channels");
  54. for (size_t i = 0; i < nChannel; ++i)
  55. {
  56. channels.append_child("channel").append_child_value("label", selectedChannelNames[i].toASCIIString()).append_child_value("unit", "unknown").
  57. append_child_value("type", "signal");
  58. }
  59. // make a new outlet
  60. m_signalOutlet = new lsl::stream_outlet(signalInfo, int(m_nSamplePerSentBlock));
  61. // Open a stimulus stream
  62. lsl::stream_info stimulusInfo(m_MarkerStreamName, "Markers", 1, lsl::IRREGULAR_RATE, lsl::cf_int32, m_MarkerStreamID);
  63. stimulusInfo.desc().append_child("channels").append_child("channel").append_child_value("label", "Stimulations").append_child_value("type", "marker");
  64. m_stimulusOutlet = new lsl::stream_outlet(stimulusInfo);
  65. m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "LSL Output activated...\n";
  66. }
  67. // m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Step from sampling rate is " << 1.0 / double(sampling) << "\n";
  68. return true;
  69. }
  70. void CPluginLSLOutput::loopHook(std::deque<std::vector<float>>& buffers, CStimulationSet& stimSet, const uint64_t start, const uint64_t end,
  71. const uint64_t /*sampleTime*/)
  72. {
  73. if (m_IsLSLOutputEnabled)
  74. {
  75. // Output signal
  76. if (m_signalOutlet->have_consumers())
  77. {
  78. const uint64_t sampleStep = (end - start) / static_cast<uint64_t>(m_nSamplePerSentBlock);
  79. if (m_useOVTimestamps)
  80. {
  81. const double sampleStepInSec = CTime(sampleStep).toSeconds();
  82. const double chunkStartInSec = CTime(start).toSeconds();
  83. for (size_t i = 0; i < m_nSamplePerSentBlock; ++i) { m_signalOutlet->push_sample(buffers[i], chunkStartInSec + double(i) * sampleStepInSec); }
  84. }
  85. else
  86. {
  87. for (size_t i = 0; i < m_nSamplePerSentBlock; ++i)
  88. {
  89. const double lslTime = OpenViBE::LabStreamLayer::getLSLRelativeTime(m_startTime + CTime(start + i * sampleStep));
  90. m_signalOutlet->push_sample(buffers[i], lslTime);
  91. }
  92. }
  93. // m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Pushed first signal at " << start << "\n";
  94. // m_kernelCtx.getLogManager() << Kernel::LogLevel_Info << "Step is " << step << "\n";
  95. }
  96. // Output stimuli
  97. if (m_stimulusOutlet->have_consumers())
  98. {
  99. for (size_t i = 0; i < stimSet.getStimulationCount(); ++i)
  100. {
  101. if (stimSet.getStimulationDate(i) >= start && stimSet.getStimulationDate(i) < end)
  102. {
  103. const int code = int(stimSet.getStimulationIdentifier(i));
  104. const double date = m_useOVTimestamps ? CTime(stimSet.getStimulationDate(i)).toSeconds()
  105. : OpenViBE::LabStreamLayer::getLSLRelativeTime(m_startTime + CTime(stimSet.getStimulationDate(i)));
  106. m_stimulusOutlet->push_sample(&code, date);
  107. }
  108. }
  109. }
  110. }
  111. }
  112. void CPluginLSLOutput::stopHook()
  113. {
  114. if (m_IsLSLOutputEnabled)
  115. {
  116. if (m_signalOutlet)
  117. {
  118. delete m_signalOutlet;
  119. m_signalOutlet = nullptr;
  120. }
  121. if (m_stimulusOutlet)
  122. {
  123. delete m_stimulusOutlet;
  124. m_stimulusOutlet = nullptr;
  125. }
  126. }
  127. }
  128. } // namespace Plugins
  129. } // namespace AcquisitionServer
  130. } // namespace OpenViBE
  131. #endif