diff --git a/LSL.cs b/LSL.cs
index ee63542..c8fbb96 100644
--- a/LSL.cs
+++ b/LSL.cs
@@ -18,8 +18,49 @@ namespace LSL
///
///
- public class liblsl
+ public abstract class LSLObject : SafeHandle
{
+ public IntPtr obj { get => handle; }
+ public LSLObject(IntPtr obj) : base(IntPtr.Zero, true)
+ {
+#if LSL_PRINT_OBJECT_LIFETIMES
+ System.Console.Out.WriteLine($"Created object {obj:X}");
+#endif
+ if (obj == IntPtr.Zero) throw new InternalException("Error creating object");
+ this.SetHandle(obj);
+ }
+
+ public override bool IsInvalid => handle == IntPtr.Zero;
+
+ ///
+ /// To be implemented in inheriting classes: the liblsl function to destroy the internal object
+ ///
+ protected abstract void DestroyLSLObject(IntPtr obj);
+
+ protected override bool ReleaseHandle()
+ {
+#if LSL_PRINT_OBJECT_LIFETIMES
+ System.Console.Out.WriteLine($"Destroying object {handle:X}");
+#endif
+ DestroyLSLObject(handle);
+ return true;
+ }
+ }
+
+ ///
+ /// Static functions implemented in liblsl
+ ///
+ public static class LSL
+ {
+ ///
+ /// Helper method to dispose a StreamInfo[] array
+ ///
+ /// Array to be disposed
+ public static void DisposeArray(this StreamInfo[] array)
+ {
+ foreach (var si in array) si.Dispose();
+ }
+
/// Constant to indicate that a stream has variable sampling rate.
public const double IRREGULAR_RATE = 0.0;
@@ -37,51 +78,6 @@ Note that significantly larger numbers can cause the timeout to be invalid on so
*/
public const double FOREVER = 32000000.0;
- /// Data format of a channel (each transmitted sample holds an array of channels).
- public enum channel_format_t : int
- {
- cf_float32 = 1, // For up to 24-bit precision measurements in the appropriate physical unit
- // (e.g., microvolts). Integers from -16777216 to 16777216 are represented accurately.
- cf_double64 = 2, // For universal numeric data as long as permitted by network & disk budget.
- // The largest representable integer is 53-bit.
- cf_string = 3, // For variable-length ASCII strings or data blobs, such as video frames,
- // complex event descriptions, etc.
- cf_int32 = 4, // For high-rate digitized formats that require 32-bit precision. Depends critically on
- // meta-data to represent meaningful units. Useful for application event codes or other coded data.
- cf_int16 = 5, // For very high rate signals (40Khz+) or consumer-grade audio
- // (for professional audio float is recommended).
- cf_int8 = 6, // For binary signals or other coded data.
- // Not recommended for encoding string data.
- cf_int64 = 7, // For now only for future compatibility. Support for this type is not yet exposed in all languages.
- // Also, some builds of liblsl will not be able to send or receive data of this type.
- cf_undefined = 0 // Can not be transmitted.
- };
-
- /**
- * Post-processing options for stream inlets.
- */
- public enum processing_options_t : int
- {
- proc_none = 0, // No automatic post-processing; return the ground-truth time stamps for manual
- // post-processing. This is the default behavior of the inlet.
-
- proc_clocksync = 1, // Perform automatic clock synchronization; equivalent to manually adding
- // the time_correction() value to the received time stamps.
-
- proc_dejitter = 2, // Remove jitter from time stamps.
- // This will apply a smoothing algorithm to the received time stamps;
- // the smoothing needs to see a minimum number of samples (30-120 seconds worst-case)
- // until the remaining jitter is consistently below 1ms.
-
- proc_monotonize = 4, // Force the time-stamps to be monotonically ascending.
- // Only makes sense if timestamps are dejittered.
-
- proc_threadsafe = 8, // Post-processing is thread-safe (same inlet can be read from by multiple threads);
- // uses somewhat more CPU.
-
- proc_ALL = 1 | 2 | 4 | 8 // The combination of all possible post-processing options.
- };
-
/**
* Protocol version.
* The major version is protocol_version() / 100;
@@ -124,312 +120,6 @@ public enum processing_options_t : int
* written to disk when recording the stream (playing a similar role as a file header).
*/
- public class StreamInfo
- {
- /**
- * Construct a new StreamInfo object.
- * Core stream information is specified here. Any remaining meta-data can be added later.
- * @param name Name of the stream. Describes the device (or product series) that this stream makes available
- * (for use by programs, experimenters or data analysts). Cannot be empty.
- * @param type Content type of the stream. Please see https://github.com/sccn/xdf/wiki/Meta-Data (or web search for:
- * XDF meta-data) for pre-defined content-type names, but you can also make up your own.
- * The content type is the preferred way to find streams (as opposed to searching by name).
- * @param channel_count Number of channels per sample. This stays constant for the lifetime of the stream.
- * @param nominal_srate The sampling rate (in Hz) as advertised by the data source, if regular (otherwise set to IRREGULAR_RATE).
- * @param channel_format Format/type of each channel. If your channels have different formats, consider supplying
- * multiple streams or use the largest type that can hold them all (such as cf_double64).
- * @param source_id Unique identifier of the device or source of the data, if available (such as the serial number).
- * This is critical for system robustness since it allows recipients to recover from failure even after the
- * serving app, device or computer crashes (just by finding a stream with the same source id on the network again).
- * Therefore, it is highly recommended to always try to provide whatever information can uniquely identify the data source itself.
- */
- public StreamInfo(string name, string type, int channel_count = 1, double nominal_srate = IRREGULAR_RATE, channel_format_t channel_format = channel_format_t.cf_float32, string source_id = "") { obj = dll.lsl_create_streaminfo(name, type, channel_count, nominal_srate, channel_format, source_id); }
- public StreamInfo(IntPtr handle) { obj = handle; }
-
- /// Destroy a previously created streaminfo object.
- ~StreamInfo() { Dispose(false); }
-
- /// Dispose of the object
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- dll.lsl_destroy_streaminfo(obj);
- obj = IntPtr.Zero;
- _disposed = true;
- }
-
- // ========================
- // === Core Information ===
- // ========================
- // (these fields are assigned at construction)
-
- /**
- * Name of the stream.
- * This is a human-readable name. For streams offered by device modules, it refers to the type of device or product series
- * that is generating the data of the stream. If the source is an application, the name may be a more generic or specific identifier.
- * Multiple streams with the same name can coexist, though potentially at the cost of ambiguity (for the recording app or experimenter).
- */
- public string name() { return Marshal.PtrToStringAnsi(dll.lsl_get_name(obj)); }
-
-
- /**
- * Content type of the stream.
- * The content type is a short string such as "EEG", "Gaze" which describes the content carried by the channel (if known).
- * If a stream contains mixed content this value need not be assigned but may instead be stored in the description of channel types.
- * To be useful to applications and automated processing systems using the recommended content types is preferred.
- * Content types usually follow those pre-defined in https://github.com/sccn/xdf/wiki/Meta-Data (or web search for: XDF meta-data).
- */
- public string type() { return Marshal.PtrToStringAnsi(dll.lsl_get_type(obj)); }
-
- /**
- * Number of channels of the stream.
- * A stream has at least one channel; the channel count stays constant for all samples.
- */
- public int channel_count() { return dll.lsl_get_channel_count(obj); }
-
- /**
- * Sampling rate of the stream, according to the source (in Hz).
- * If a stream is irregularly sampled, this should be set to IRREGULAR_RATE.
- *
- * Note that no data will be lost even if this sampling rate is incorrect or if a device has temporary
- * hiccups, since all samples will be recorded anyway (except for those dropped by the device itself). However,
- * when the recording is imported into an application, a good importer may correct such errors more accurately
- * if the advertised sampling rate was close to the specs of the device.
- */
- public double nominal_srate() { return dll.lsl_get_nominal_srate(obj); }
-
- /**
- * Channel format of the stream.
- * All channels in a stream have the same format. However, a device might offer multiple time-synched streams
- * each with its own format.
- */
- public channel_format_t channel_format() { return dll.lsl_get_channel_format(obj); }
-
- /**
- * Unique identifier of the stream's source, if available.
- * The unique source (or device) identifier is an optional piece of information that, if available, allows that
- * endpoints (such as the recording program) can re-acquire a stream automatically once it is back online.
- */
- public string source_id() { return Marshal.PtrToStringAnsi(dll.lsl_get_source_id(obj)); }
-
-
- // ======================================
- // === Additional Hosting Information ===
- // ======================================
- // (these fields are implicitly assigned once bound to an outlet/inlet)
-
- /**
- * Protocol version used to deliver the stream.
- */
- public int version() { return dll.lsl_get_version(obj); }
-
- /**
- * Creation time stamp of the stream.
- * This is the time stamp when the stream was first created
- * (as determined via local_clock() on the providing machine).
- */
- public double created_at() { return dll.lsl_get_created_at(obj); }
-
- /**
- * Unique ID of the stream outlet instance (once assigned).
- * This is a unique identifier of the stream outlet, and is guaranteed to be different
- * across multiple instantiations of the same outlet (e.g., after a re-start).
- */
- public string uid() { return Marshal.PtrToStringAnsi(dll.lsl_get_uid(obj)); }
-
- /**
- * Session ID for the given stream.
- * The session id is an optional human-assigned identifier of the recording session.
- * While it is rarely used, it can be used to prevent concurrent recording activitites
- * on the same sub-network (e.g., in multiple experiment areas) from seeing each other's streams
- * (assigned via a configuration file by the experimenter, see Network Connectivity in the LSL wiki).
- */
- public string session_id() { return Marshal.PtrToStringAnsi(dll.lsl_get_session_id(obj)); }
-
- /**
- * Hostname of the providing machine.
- */
- public string hostname() { return Marshal.PtrToStringAnsi(dll.lsl_get_hostname(obj)); }
-
-
- // ========================
- // === Data Description ===
- // ========================
-
- /**
- * Extended description of the stream.
- * It is highly recommended that at least the channel labels are described here.
- * See code examples on the LSL wiki. Other information, such as amplifier settings,
- * measurement units if deviating from defaults, setup information, subject information, etc.,
- * can be specified here, as well. Meta-data recommendations follow the XDF file format project
- * (github.com/sccn/xdf/wiki/Meta-Data or web search for: XDF meta-data).
- *
- * Important: if you use a stream content type for which meta-data recommendations exist, please
- * try to lay out your meta-data in agreement with these recommendations for compatibility with other applications.
- */
- public XMLElement desc() { return new XMLElement(dll.lsl_get_desc(obj)); }
-
- /**
- * Retrieve the entire stream_info in XML format.
- * This yields an XML document (in string form) whose top-level element is . The info element contains
- * one element for each field of the stream_info class, including:
- * a) the core elements , , , , ,
- * b) the misc elements , , , , , , , , ,
- * c) the extended description element with user-defined sub-elements.
- */
- public string as_xml()
- {
- IntPtr pXml = dll.lsl_get_xml(obj);
- string strXml = Marshal.PtrToStringAnsi(pXml);
- dll.lsl_destroy_string(pXml);
- return strXml;
- }
-
-
- /**
- * Get access to the underlying handle.
- */
- public IntPtr handle() { return obj; }
-
- private IntPtr obj;
- }
-
-
- // =======================
- // ==== Stream Outlet ====
- // =======================
-
- /**
- * A stream outlet.
- * Outlets are used to make streaming data (and the meta-data) available on the lab network.
- */
- public class StreamOutlet
- {
- /**
- * Establish a new stream outlet. This makes the stream discoverable.
- * @param info The stream information to use for creating this stream. Stays constant over the lifetime of the outlet.
- * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission. If unspecified,
- * each push operation yields one chunk. Inlets can override this setting.
- * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a nominal
- * sampling rate, otherwise x100 in samples). The default is 6 minutes of data.
- */
- public StreamOutlet(StreamInfo info, int chunk_size = 0, int max_buffered = 360) { obj = dll.lsl_create_outlet(info.handle(), chunk_size, max_buffered); }
-
- ~StreamOutlet() { Dispose(false); }
-
- /**
- * Dispose.
- * The stream will no longer be discoverable after disposal (or when disposed by the GC) and all paired inlets will stop delivering data.
- */
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
-
- dll.lsl_destroy_outlet(obj);
- obj = IntPtr.Zero;
- _disposed = true;
- }
-
-
- // ========================================
- // === Pushing a sample into the outlet ===
- // ========================================
-
- /**
- * Push an array of values as a sample into the outlet.
- * Each entry in the vector corresponds to one channel.
- * @param data An array of values to push (one for each channel).
- * @param timestamp Optionally the capture time of the sample, in agreement with local_clock(); if omitted, the current time is used.
- * @param pushthrough Optionally whether to push the sample through to the receivers instead of buffering it with subsequent samples.
- * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
- */
- public void push_sample(float[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ftp(obj, data, timestamp, pushthrough ? 1 : 0); }
- public void push_sample(double[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_dtp(obj, data, timestamp, pushthrough ? 1 : 0); }
- public void push_sample(int[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_itp(obj, data, timestamp, pushthrough ? 1 : 0); }
- public void push_sample(short[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_stp(obj, data, timestamp, pushthrough ? 1 : 0); }
- public void push_sample(char[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ctp(obj, data, timestamp, pushthrough ? 1 : 0); }
- public void push_sample(string[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_strtp(obj, data, timestamp, pushthrough ? 1 : 0); }
-
-
- // ===================================================
- // === Pushing an chunk of samples into the outlet ===
- // ===================================================
-
- /**
- * Push a chunk of samples into the outlet. Single timestamp provided.
- * @param data A rectangular array of values for multiple samples.
- * @param timestamp Optionally the capture time of the most recent sample, in agreement with local_clock(); if omitted, the current time is used.
- * The time stamps of other samples are automatically derived based on the sampling rate of the stream.
- * @param pushthrough Optionally whether to push the chunk through to the receivers instead of buffering it with subsequent samples.
- * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
- */
- public void push_chunk(float[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ftp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- public void push_chunk(double[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_dtp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- public void push_chunk(int[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_itp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- public void push_chunk(short[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_stp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- public void push_chunk(char[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ctp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- public void push_chunk(string[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_strtp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
-
- /**
- * Push a chunk of multiplexed samples into the outlet. One timestamp per sample is provided.
- * @param data A rectangular array of values for multiple samples.
- * @param timestamps An array of timestamp values holding time stamps for each sample in the data buffer.
- * @param pushthrough Optionally whether to push the chunk through to the receivers instead of buffering it with subsequent samples.
- * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
- */
- public void push_chunk(float[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_ftnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- public void push_chunk(double[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_dtnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- public void push_chunk(int[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_itnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- public void push_chunk(short[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_stnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- public void push_chunk(char[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_ctnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- public void push_chunk(string[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_strtnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
-
-
- // ===============================
- // === Miscellaneous Functions ===
- // ===============================
-
- /**
- * Check whether consumers are currently registered.
- * While it does not hurt, there is technically no reason to push samples if there is no consumer.
- */
- public bool have_consumers() { return dll.lsl_have_consumers(obj) > 0; }
-
- /**
- * Wait until some consumer shows up (without wasting resources).
- * @return True if the wait was successful, false if the timeout expired.
- */
- public bool wait_for_consumers(double timeout = FOREVER) { return dll.lsl_wait_for_consumers(obj) > 0; }
-
- /**
- * Retrieve the stream info provided by this outlet.
- * This is what was used to create the stream (and also has the Additional Network Information fields assigned).
- */
- public StreamInfo info() { return new StreamInfo(dll.lsl_get_info(obj)); }
-
- private IntPtr obj;
- }
-
-
// ===========================
// ==== Resolve Functions ====
// ===========================
@@ -468,7 +158,7 @@ public static StreamInfo[] resolve_streams(double wait_time = 1.0)
* @return An array of matching stream info objects (excluding their meta-data), any of
* which can subsequently be used to open an inlet.
*/
- public static StreamInfo[] resolve_stream(string prop, string value, int minimum = 1, double timeout = FOREVER)
+ public static StreamInfo[] resolve_stream(string prop, string value, int minimum = 1, double timeout = LSL.FOREVER)
{
IntPtr[] buf = new IntPtr[1024]; int num = dll.lsl_resolve_byprop(buf, (uint)buf.Length, prop, value, minimum, timeout);
StreamInfo[] res = new StreamInfo[num];
@@ -488,7 +178,7 @@ public static StreamInfo[] resolve_stream(string prop, string value, int minimum
* @return An array of matching stream info objects (excluding their meta-data), any of
* which can subsequently be used to open an inlet.
*/
- public static StreamInfo[] resolve_stream(string pred, int minimum = 1, double timeout = FOREVER)
+ public static StreamInfo[] resolve_stream(string pred, int minimum = 1, double timeout = LSL.FOREVER)
{
IntPtr[] buf = new IntPtr[1024]; int num = dll.lsl_resolve_bypred(buf, (uint)buf.Length, pred, minimum, timeout);
StreamInfo[] res = new StreamInfo[num];
@@ -497,760 +187,1017 @@ public static StreamInfo[] resolve_stream(string pred, int minimum = 1, double t
return res;
}
+ /// Check an error condition and throw an exception if appropriate.
+ public static void check_error(int ec)
+ {
+ if (ec < 0)
+ switch (ec)
+ {
+ case -1: throw new TimeoutException("The operation failed due to a timeout.");
+ case -2: throw new LostException("The stream has been lost.");
+ case -3: throw new ArgumentException("An argument was incorrectly specified (e.g., wrong format or wrong length).");
+ case -4: throw new InternalException("An internal internal error has occurred.");
+ default: throw new Exception("An unknown error has occurred.");
+ }
+ }
+ }
- // ======================
- // ==== Stream Inlet ====
- // ======================
+ /// Data format of a channel (each transmitted sample holds an array of channels).
+ public enum channel_format_t : int
+ {
+ cf_float32 = 1, // For up to 24-bit precision measurements in the appropriate physical unit
+ // (e.g., microvolts). Integers from -16777216 to 16777216 are represented accurately.
+ cf_double64 = 2, // For universal numeric data as long as permitted by network & disk budget.
+ // The largest representable integer is 53-bit.
+ cf_string = 3, // For variable-length ASCII strings or data blobs, such as video frames,
+ // complex event descriptions, etc.
+ cf_int32 = 4, // For high-rate digitized formats that require 32-bit precision. Depends critically on
+ // meta-data to represent meaningful units. Useful for application event codes or other coded data.
+ cf_int16 = 5, // For very high rate signals (40Khz+) or consumer-grade audio
+ // (for professional audio float is recommended).
+ cf_int8 = 6, // For binary signals or other coded data.
+ // Not recommended for encoding string data.
+ cf_int64 = 7, // For now only for future compatibility. Support for this type is not yet exposed in all languages.
+ // Also, some builds of liblsl will not be able to send or receive data of this type.
+ cf_undefined = 0 // Can not be transmitted.
+ };
+
+ /**
+ * Post-processing options for stream inlets.
+ */
+ public enum processing_options_t : int
+ {
+ proc_none = 0, // No automatic post-processing; return the ground-truth time stamps for manual
+ // post-processing. This is the default behavior of the inlet.
- /**
- * A stream inlet.
- * Inlets are used to receive streaming data (and meta-data) from the lab network.
- */
- public class StreamInlet
- {
- /**
- * Construct a new stream inlet from a resolved stream info.
- * @param info A resolved stream info object (as coming from one of the resolver functions).
- * Note: the stream_inlet may also be constructed with a fully-specified stream_info,
- * if the desired channel format and count is already known up-front, but this is
- * strongly discouraged and should only ever be done if there is no time to resolve the
- * stream up-front (e.g., due to limitations in the client program).
- * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a nominal
- * sampling rate, otherwise x100 in samples). Recording applications want to use a fairly
- * large buffer size here, while real-time applications would only buffer as much as
- * they need to perform their next calculation.
- * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted
- * (the default corresponds to the chunk sizes used by the sender).
- * Recording applications can use a generous size here (leaving it to the network how
- * to pack things), while real-time applications may want a finer (perhaps 1-sample) granularity.
- If left unspecified (=0), the sender determines the chunk granularity.
- * @param recover Try to silently recover lost streams that are recoverable (=those that that have a source_id set).
- * In all other cases (recover is false or the stream is not recoverable) functions may throw a
- * LostException if the stream's source is lost (e.g., due to an app or computer crash).
- */
- public StreamInlet(StreamInfo info, int max_buflen = 360, int max_chunklen = 0, bool recover = true, processing_options_t postproc_flags = processing_options_t.proc_none)
- {
- obj = dll.lsl_create_inlet(info.handle(), max_buflen, max_chunklen, recover ? 1 : 0);
- dll.lsl_set_postprocessing(obj, postproc_flags);
- }
+ proc_clocksync = 1, // Perform automatic clock synchronization; equivalent to manually adding
+ // the time_correction() value to the received time stamps.
- ~StreamInlet() { Dispose(false); }
+ proc_dejitter = 2, // Remove jitter from time stamps.
+ // This will apply a smoothing algorithm to the received time stamps;
+ // the smoothing needs to see a minimum number of samples (30-120 seconds worst-case)
+ // until the remaining jitter is consistently below 1ms.
- /**
- * Dispose
- * The inlet will be disconnect after disposal (or when disposed by the GC)
- */
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
- {
- if (_disposed)
- {
- return;
- }
+ proc_monotonize = 4, // Force the time-stamps to be monotonically ascending.
+ // Only makes sense if timestamps are dejittered.
- dll.lsl_destroy_inlet(obj);
- obj = IntPtr.Zero;
- _disposed = true;
- }
+ proc_threadsafe = 8, // Post-processing is thread-safe (same inlet can be read from by multiple threads);
+ // uses somewhat more CPU.
- /**
- * Retrieve the complete information of the given stream, including the extended description.
- * Can be invoked at any time of the stream's lifetime.
- * @param timeout Timeout of the operation (default: no timeout).
- * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
- */
- public StreamInfo info(double timeout = FOREVER) { int ec = 0; IntPtr res = dll.lsl_get_fullinfo(obj, timeout, ref ec); check_error(ec); return new StreamInfo(res); }
-
- /**
- * Subscribe to the data stream.
- * All samples pushed in at the other end from this moment onwards will be queued and
- * eventually be delivered in response to pull_sample() or pull_chunk() calls.
- * Pulling a sample without some preceding open_stream is permitted (the stream will then be opened implicitly).
- * @param timeout Optional timeout of the operation (default: no timeout).
- * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
- */
- public void open_stream(double timeout = FOREVER) { int ec = 0; dll.lsl_open_stream(obj, timeout, ref ec); check_error(ec); }
-
- /**
- * Drop the current data stream.
- * All samples that are still buffered or in flight will be dropped and transmission
- * and buffering of data for this inlet will be stopped. If an application stops being
- * interested in data from a source (temporarily or not) but keeps the outlet alive,
- * it should call close_stream() to not waste unnecessary system and network
- * resources.
- */
- public void close_stream() { dll.lsl_close_stream(obj); }
-
- /**
- * Retrieve an estimated time correction offset for the given stream.
- * The first call to this function takes several miliseconds until a reliable first estimate is obtained.
- * Subsequent calls are instantaneous (and rely on periodic background updates).
- * The precision of these estimates should be below 1 ms (empirically within +/-0.2 ms).
- * @timeout Timeout to acquire the first time-correction estimate (default: no timeout).
- * @return The time correction estimate. This is the number that needs to be added to a time stamp
- * that was remotely generated via lsl_local_clock() to map it into the local clock domain of this machine.
- * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
- */
- public double time_correction(double timeout = FOREVER) { int ec = 0; double res = dll.lsl_time_correction(obj, timeout, ref ec); check_error(ec); return res; }
-
- // =======================================
- // === Pulling a sample from the inlet ===
- // =======================================
-
- /**
- * Pull a sample from the inlet and read it into an array of values.
- * Handles type checking & conversion.
- * @param sample An array to hold the resulting values.
- * @param timeout The timeout for this operation, if any. Use 0.0 to make the function non-blocking.
- * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was available.
- * To remap this time stamp to the local clock, add the value returned by .time_correction() to it.
- * @throws LostException (if the stream source has been lost).
- */
- public double pull_sample(float[] sample, double timeout = FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_f(obj, sample, sample.Length, timeout, ref ec); check_error(ec); return res; }
- public double pull_sample(double[] sample, double timeout = FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_d(obj, sample, sample.Length, timeout, ref ec); check_error(ec); return res; }
- public double pull_sample(int[] sample, double timeout = FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_i(obj, sample, sample.Length, timeout, ref ec); check_error(ec); return res; }
- public double pull_sample(short[] sample, double timeout = FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_s(obj, sample, sample.Length, timeout, ref ec); check_error(ec); return res; }
- public double pull_sample(char[] sample, double timeout = FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_c(obj, sample, sample.Length, timeout, ref ec); check_error(ec); return res; }
- public double pull_sample(string[] sample, double timeout = FOREVER)
- {
- int ec = 0;
- IntPtr[] tmp = new IntPtr[sample.Length];
- double res = dll.lsl_pull_sample_str(obj, tmp, tmp.Length, timeout, ref ec); check_error(ec);
- try
- {
- for (int k = 0; k < tmp.Length; k++)
- sample[k] = Marshal.PtrToStringAnsi(tmp[k]);
- }
- finally
- {
- for (int k = 0; k < tmp.Length; k++)
- dll.lsl_destroy_string(tmp[k]);
- }
- return res;
- }
+ proc_ALL = 1 | 2 | 4 | 8 // The combination of all possible post-processing options.
+ };
+ public class StreamInfo : LSLObject
+ {
+ /**
+ * Construct a new StreamInfo object.
+ * Core stream information is specified here. Any remaining meta-data can be added later.
+ * @param name Name of the stream. Describes the device (or product series) that this stream makes available
+ * (for use by programs, experimenters or data analysts). Cannot be empty.
+ * @param type Content type of the stream. Please see https://github.com/sccn/xdf/wiki/Meta-Data (or web search for:
+ * XDF meta-data) for pre-defined content-type names, but you can also make up your own.
+ * The content type is the preferred way to find streams (as opposed to searching by name).
+ * @param channel_count Number of channels per sample. This stays constant for the lifetime of the stream.
+ * @param nominal_srate The sampling rate (in Hz) as advertised by the data source, if regular (otherwise set to IRREGULAR_RATE).
+ * @param channel_format Format/type of each channel. If your channels have different formats, consider supplying
+ * multiple streams or use the largest type that can hold them all (such as cf_double64).
+ * @param source_id Unique identifier of the device or source of the data, if available (such as the serial number).
+ * This is critical for system robustness since it allows recipients to recover from failure even after the
+ * serving app, device or computer crashes (just by finding a stream with the same source id on the network again).
+ * Therefore, it is highly recommended to always try to provide whatever information can uniquely identify the data source itself.
+ */
+ public StreamInfo(string name, string type, int channel_count = 1, double nominal_srate = LSL.IRREGULAR_RATE, channel_format_t channel_format = channel_format_t.cf_float32, string source_id = "")
+ : base(dll.lsl_create_streaminfo(name, type, channel_count, nominal_srate, channel_format, source_id)) { }
+ public StreamInfo(IntPtr handle) : base(handle) { }
- // =================================================
- // === Pulling a chunk of samples from the inlet ===
- // =================================================
-
- /**
- * Pull a chunk of data from the inlet.
- * @param data_buffer A pre-allocated buffer where the channel data shall be stored.
- * @param timestamp_buffer A pre-allocated buffer where time stamps shall be stored.
- * @param timeout Optionally the timeout for this operation, if any. When the timeout expires, the function
- * may return before the entire buffer is filled. The default value of 0.0 will retrieve only
- * data available for immediate pickup.
- * @return samples_written Number of samples written to the data and timestamp buffers.
- * @throws LostException (if the stream source has been lost).
- */
- public int pull_chunk(float[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_f(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); check_error(ec); return (int)res / data_buffer.GetLength(1); }
- public int pull_chunk(double[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_d(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); check_error(ec); return (int)res / data_buffer.GetLength(1); }
- public int pull_chunk(int[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_i(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); check_error(ec); return (int)res / data_buffer.GetLength(1); }
- public int pull_chunk(short[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_s(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); check_error(ec); return (int)res / data_buffer.GetLength(1); }
- public int pull_chunk(char[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_c(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); check_error(ec); return (int)res / data_buffer.GetLength(1); }
- public int pull_chunk(string[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0)
- {
- int ec = 0;
- IntPtr[,] tmp = new IntPtr[data_buffer.GetLength(0), data_buffer.GetLength(1)];
- uint res = dll.lsl_pull_chunk_str(obj, tmp, timestamp_buffer, (uint)tmp.Length, (uint)timestamp_buffer.Length, timeout, ref ec);
- check_error(ec);
- try
- {
- for (int s = 0; s < tmp.GetLength(0); s++)
- for (int c = 0; c < tmp.GetLength(1); c++)
- data_buffer[s, c] = Marshal.PtrToStringAnsi(tmp[s, c]);
- }
- finally
- {
- for (int s = 0; s < tmp.GetLength(0); s++)
- for (int c = 0; c < tmp.GetLength(1); c++)
- dll.lsl_destroy_string(tmp[s, c]);
- }
- return (int)res / data_buffer.GetLength(1);
- }
+ protected override void DestroyLSLObject(IntPtr obj) { dll.lsl_destroy_streaminfo(obj); }
- /**
- * Query whether samples are currently available for immediate pickup.
- * Note that it is not a good idea to use samples_available() to determine whether
- * a pull_*() call would block: to be sure, set the pull timeout to 0.0 or an acceptably
- * low value. If the underlying implementation supports it, the value will be the number of
- * samples available (otherwise it will be 1 or 0).
- */
- public int samples_available() { return (int)dll.lsl_samples_available(obj); }
-
- /**
- * Query whether the clock was potentially reset since the last call to was_clock_reset().
- * This is a rarely-used function that is only useful to applications that combine multiple time_correction
- * values to estimate precise clock drift; it allows to tolerate cases where the source machine was
- * hot-swapped or restarted in between two measurements.
- */
- public bool was_clock_reset() { return (int)dll.lsl_was_clock_reset(obj) != 0; }
-
- private IntPtr obj;
- }
+ // ========================
+ // === Core Information ===
+ // ========================
+ // (these fields are assigned at construction)
+ /**
+ * Name of the stream.
+ * This is a human-readable name. For streams offered by device modules, it refers to the type of device or product series
+ * that is generating the data of the stream. If the source is an application, the name may be a more generic or specific identifier.
+ * Multiple streams with the same name can coexist, though potentially at the cost of ambiguity (for the recording app or experimenter).
+ */
+ public string name() { return Marshal.PtrToStringAnsi(dll.lsl_get_name(obj)); }
- // =====================
- // ==== XML Element ====
- // =====================
/**
- * A lightweight XML element tree; models the .desc() field of stream_info.
- * Has a name and can have multiple named children or have text content as value; attributes are omitted.
- * Insider note: The interface is modeled after a subset of pugixml's node type and is compatible with it.
- * See also http://pugixml.googlecode.com/svn/tags/latest/docs/manual/access.html for additional documentation.
+ * Content type of the stream.
+ * The content type is a short string such as "EEG", "Gaze" which describes the content carried by the channel (if known).
+ * If a stream contains mixed content this value need not be assigned but may instead be stored in the description of channel types.
+ * To be useful to applications and automated processing systems using the recommended content types is preferred.
+ * Content types usually follow those pre-defined in https://github.com/sccn/xdf/wiki/Meta-Data (or web search for: XDF meta-data).
*/
- public struct XMLElement
- {
- public XMLElement(IntPtr handle) { obj = handle; }
+ public string type() { return Marshal.PtrToStringAnsi(dll.lsl_get_type(obj)); }
- // === Tree Navigation ===
+ /**
+ * Number of channels of the stream.
+ * A stream has at least one channel; the channel count stays constant for all samples.
+ */
+ public int channel_count() { return dll.lsl_get_channel_count(obj); }
- /// Get the first child of the element.
- public XMLElement first_child() { return new XMLElement(dll.lsl_first_child(obj)); }
+ /**
+ * Sampling rate of the stream, according to the source (in Hz).
+ * If a stream is irregularly sampled, this should be set to IRREGULAR_RATE.
+ *
+ * Note that no data will be lost even if this sampling rate is incorrect or if a device has temporary
+ * hiccups, since all samples will be recorded anyway (except for those dropped by the device itself). However,
+ * when the recording is imported into an application, a good importer may correct such errors more accurately
+ * if the advertised sampling rate was close to the specs of the device.
+ */
+ public double nominal_srate() { return dll.lsl_get_nominal_srate(obj); }
- /// Get the last child of the element.
- public XMLElement last_child() { return new XMLElement(dll.lsl_last_child(obj)); }
+ /**
+ * Channel format of the stream.
+ * All channels in a stream have the same format. However, a device might offer multiple time-synched streams
+ * each with its own format.
+ */
+ public channel_format_t channel_format() { return dll.lsl_get_channel_format(obj); }
- /// Get the next sibling in the children list of the parent node.
- public XMLElement next_sibling() { return new XMLElement(dll.lsl_next_sibling(obj)); }
+ /**
+ * Unique identifier of the stream's source, if available.
+ * The unique source (or device) identifier is an optional piece of information that, if available, allows that
+ * endpoints (such as the recording program) can re-acquire a stream automatically once it is back online.
+ */
+ public string source_id() { return Marshal.PtrToStringAnsi(dll.lsl_get_source_id(obj)); }
- /// Get the previous sibling in the children list of the parent node.
- public XMLElement previous_sibling() { return new XMLElement(dll.lsl_previous_sibling(obj)); }
- /// Get the parent node.
- public XMLElement parent() { return new XMLElement(dll.lsl_parent(obj)); }
+ // ======================================
+ // === Additional Hosting Information ===
+ // ======================================
+ // (these fields are implicitly assigned once bound to an outlet/inlet)
+ /**
+ * Protocol version used to deliver the stream.
+ */
+ public int version() { return dll.lsl_get_version(obj); }
- // === Tree Navigation by Name ===
+ /**
+ * Creation time stamp of the stream.
+ * This is the time stamp when the stream was first created
+ * (as determined via local_clock() on the providing machine).
+ */
+ public double created_at() { return dll.lsl_get_created_at(obj); }
- /// Get a child with a specified name.
- public XMLElement child(string name) { return new XMLElement(dll.lsl_child(obj, name)); }
+ /**
+ * Unique ID of the stream outlet instance (once assigned).
+ * This is a unique identifier of the stream outlet, and is guaranteed to be different
+ * across multiple instantiations of the same outlet (e.g., after a re-start).
+ */
+ public string uid() { return Marshal.PtrToStringAnsi(dll.lsl_get_uid(obj)); }
- /// Get the next sibling with the specified name.
- public XMLElement next_sibling(string name) { return new XMLElement(dll.lsl_next_sibling_n(obj, name)); }
+ /**
+ * Session ID for the given stream.
+ * The session id is an optional human-assigned identifier of the recording session.
+ * While it is rarely used, it can be used to prevent concurrent recording activitites
+ * on the same sub-network (e.g., in multiple experiment areas) from seeing each other's streams
+ * (assigned via a configuration file by the experimenter, see Network Connectivity in the LSL wiki).
+ */
+ public string session_id() { return Marshal.PtrToStringAnsi(dll.lsl_get_session_id(obj)); }
- /// Get the previous sibling with the specified name.
- public XMLElement previous_sibling(string name) { return new XMLElement(dll.lsl_previous_sibling_n(obj, name)); }
+ /**
+ * Hostname of the providing machine.
+ */
+ public string hostname() { return Marshal.PtrToStringAnsi(dll.lsl_get_hostname(obj)); }
- // === Content Queries ===
+ // ========================
+ // === Data Description ===
+ // ========================
- /// Whether this node is empty.
- public bool empty() { return dll.lsl_empty(obj) != 0; }
+ /**
+ * Extended description of the stream.
+ * It is highly recommended that at least the channel labels are described here.
+ * See code examples on the LSL wiki. Other information, such as amplifier settings,
+ * measurement units if deviating from defaults, setup information, subject information, etc.,
+ * can be specified here, as well. Meta-data recommendations follow the XDF file format project
+ * (github.com/sccn/xdf/wiki/Meta-Data or web search for: XDF meta-data).
+ *
+ * Important: if you use a stream content type for which meta-data recommendations exist, please
+ * try to lay out your meta-data in agreement with these recommendations for compatibility with other applications.
+ */
+ public XMLElement desc() { return new XMLElement(dll.lsl_get_desc(obj)); }
- /// Whether this is a text body (instead of an XML element). True both for plain char data and CData.
- public bool is_text() { return dll.lsl_is_text(obj) != 0; }
+ /**
+ * Retrieve the entire stream_info in XML format.
+ * This yields an XML document (in string form) whose top-level element is . The info element contains
+ * one element for each field of the stream_info class, including:
+ * a) the core elements , , , , ,
+ * b) the misc elements , , , , , , , , ,
+ * c) the extended description element with user-defined sub-elements.
+ */
+ public string as_xml()
+ {
+ IntPtr pXml = dll.lsl_get_xml(obj);
+ string strXml = Marshal.PtrToStringAnsi(pXml);
+ dll.lsl_destroy_string(pXml);
+ return strXml;
+ }
+ }
- /// Name of the element.
- public string name() { return Marshal.PtrToStringAnsi(dll.lsl_name(obj)); }
- /// Value of the element.
- public string value() { return Marshal.PtrToStringAnsi(dll.lsl_value(obj)); }
+ // =======================
+ // ==== Stream Outlet ====
+ // =======================
- /// Get child value (value of the first child that is text).
- public string child_value() { return Marshal.PtrToStringAnsi(dll.lsl_child_value(obj)); }
+ /**
+ * A stream outlet.
+ * Outlets are used to make streaming data (and the meta-data) available on the lab network.
+ */
+ public class StreamOutlet : LSLObject
+ {
+ /**
+ * Establish a new stream outlet. This makes the stream discoverable.
+ * @param info The stream information to use for creating this stream. Stays constant over the lifetime of the outlet.
+ * @param chunk_size Optionally the desired chunk granularity (in samples) for transmission. If unspecified,
+ * each push operation yields one chunk. Inlets can override this setting.
+ * @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a nominal
+ * sampling rate, otherwise x100 in samples). The default is 6 minutes of data.
+ */
+ public StreamOutlet(StreamInfo info, int chunk_size = 0, int max_buffered = 360)
+ : base(dll.lsl_create_outlet(info.DangerousGetHandle(), chunk_size, max_buffered)) { }
- /// Get child value of a child with a specified name.
- public string child_value(string name) { return Marshal.PtrToStringAnsi(dll.lsl_child_value_n(obj, name)); }
+ protected override void DestroyLSLObject(IntPtr obj)
+ {
+ dll.lsl_destroy_outlet(obj);
+ }
+ // ========================================
+ // === Pushing a sample into the outlet ===
+ // ========================================
- // === Modification ===
+ /**
+ * Push an array of values as a sample into the outlet.
+ * Each entry in the vector corresponds to one channel.
+ * @param data An array of values to push (one for each channel).
+ * @param timestamp Optionally the capture time of the sample, in agreement with local_clock(); if omitted, the current time is used.
+ * @param pushthrough Optionally whether to push the sample through to the receivers instead of buffering it with subsequent samples.
+ * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
+ */
+ public void push_sample(float[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ftp(obj, data, timestamp, pushthrough ? 1 : 0); }
+ public void push_sample(double[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_dtp(obj, data, timestamp, pushthrough ? 1 : 0); }
+ public void push_sample(int[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_itp(obj, data, timestamp, pushthrough ? 1 : 0); }
+ public void push_sample(short[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_stp(obj, data, timestamp, pushthrough ? 1 : 0); }
+ public void push_sample(char[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ctp(obj, data, timestamp, pushthrough ? 1 : 0); }
+ public void push_sample(string[] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_sample_strtp(obj, data, timestamp, pushthrough ? 1 : 0); }
- /**
- * Append a child node with a given name, which has a (nameless) plain-text child with the given text value.
- */
- public XMLElement append_child_value(string name, string value) { return new XMLElement(dll.lsl_append_child_value(obj, name, value)); }
- /**
- * Prepend a child node with a given name, which has a (nameless) plain-text child with the given text value.
- */
- public XMLElement prepend_child_value(string name, string value) { return new XMLElement(dll.lsl_prepend_child_value(obj, name, value)); }
+ // ===================================================
+ // === Pushing an chunk of samples into the outlet ===
+ // ===================================================
- /**
- * Set the text value of the (nameless) plain-text child of a named child node.
- */
- public bool set_child_value(string name, string value) { return dll.lsl_set_child_value(obj, name, value) != 0; }
+ /**
+ * Push a chunk of samples into the outlet. Single timestamp provided.
+ * @param data A rectangular array of values for multiple samples.
+ * @param timestamp Optionally the capture time of the most recent sample, in agreement with local_clock(); if omitted, the current time is used.
+ * The time stamps of other samples are automatically derived based on the sampling rate of the stream.
+ * @param pushthrough Optionally whether to push the chunk through to the receivers instead of buffering it with subsequent samples.
+ * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
+ */
+ public void push_chunk(float[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ftp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
+ public void push_chunk(double[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_dtp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
+ public void push_chunk(int[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_itp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
+ public void push_chunk(short[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_stp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
+ public void push_chunk(char[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ctp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
+ public void push_chunk(string[,] data, double timestamp = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_strtp(obj, data, (uint)data.Length, timestamp, pushthrough ? 1 : 0); }
- /**
- * Set the element's name.
- * @return False if the node is empty.
- */
- public bool set_name(string rhs) { return dll.lsl_set_name(obj, rhs) != 0; }
+ /**
+ * Push a chunk of multiplexed samples into the outlet. One timestamp per sample is provided.
+ * @param data A rectangular array of values for multiple samples.
+ * @param timestamps An array of timestamp values holding time stamps for each sample in the data buffer.
+ * @param pushthrough Optionally whether to push the chunk through to the receivers instead of buffering it with subsequent samples.
+ * Note that the chunk_size, if specified at outlet construction, takes precedence over the pushthrough flag.
+ */
+ public void push_chunk(float[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_ftnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
+ public void push_chunk(double[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_dtnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
+ public void push_chunk(int[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_itnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
+ public void push_chunk(short[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_stnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
+ public void push_chunk(char[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_ctnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
+ public void push_chunk(string[,] data, double[] timestamps, bool pushthrough = true) { dll.lsl_push_chunk_strtnp(obj, data, (uint)data.Length, timestamps, pushthrough ? 1 : 0); }
- /**
- * Set the element's value.
- * @return False if the node is empty.
- */
- public bool set_value(string rhs) { return dll.lsl_set_value(obj, rhs) != 0; }
- /// Append a child element with the specified name.
- public XMLElement append_child(string name) { return new XMLElement(dll.lsl_append_child(obj, name)); }
+ // ===============================
+ // === Miscellaneous Functions ===
+ // ===============================
- /// Prepend a child element with the specified name.
- public XMLElement prepend_child(string name) { return new XMLElement(dll.lsl_prepend_child(obj, name)); }
+ /**
+ * Check whether consumers are currently registered.
+ * While it does not hurt, there is technically no reason to push samples if there is no consumer.
+ */
+ public bool have_consumers() { return dll.lsl_have_consumers(obj) > 0; }
- /// Append a copy of the specified element as a child.
- public XMLElement append_copy(XMLElement e) { return new XMLElement(dll.lsl_append_copy(obj, e.obj)); }
+ /**
+ * Wait until some consumer shows up (without wasting resources).
+ * @return True if the wait was successful, false if the timeout expired.
+ */
+ public bool wait_for_consumers(double timeout = LSL.FOREVER) { return dll.lsl_wait_for_consumers(obj) > 0; }
- /// Prepend a child element with the specified name.
- public XMLElement prepend_copy(XMLElement e) { return new XMLElement(dll.lsl_prepend_copy(obj, e.obj)); }
+ /**
+ * Retrieve the stream info provided by this outlet.
+ * This is what was used to create the stream (and also has the Additional Network Information fields assigned).
+ */
+ public StreamInfo info() { return new StreamInfo(dll.lsl_get_info(obj)); }
+ }
- /// Remove a child element with the specified name.
- public void remove_child(string name) { dll.lsl_remove_child_n(obj, name); }
- /// Remove a specified child element.
- public void remove_child(XMLElement e) { dll.lsl_remove_child(obj, e.obj); }
+ // ======================
+ // ==== Stream Inlet ====
+ // ======================
- IntPtr obj;
+ /**
+ * A stream inlet.
+ * Inlets are used to receive streaming data (and meta-data) from the lab network.
+ */
+ public class StreamInlet : LSLObject
+ {
+ /**
+ * Construct a new stream inlet from a resolved stream info.
+ * @param info A resolved stream info object (as coming from one of the resolver functions).
+ * Note: the stream_inlet may also be constructed with a fully-specified stream_info,
+ * if the desired channel format and count is already known up-front, but this is
+ * strongly discouraged and should only ever be done if there is no time to resolve the
+ * stream up-front (e.g., due to limitations in the client program).
+ * @param max_buflen Optionally the maximum amount of data to buffer (in seconds if there is a nominal
+ * sampling rate, otherwise x100 in samples). Recording applications want to use a fairly
+ * large buffer size here, while real-time applications would only buffer as much as
+ * they need to perform their next calculation.
+ * @param max_chunklen Optionally the maximum size, in samples, at which chunks are transmitted
+ * (the default corresponds to the chunk sizes used by the sender).
+ * Recording applications can use a generous size here (leaving it to the network how
+ * to pack things), while real-time applications may want a finer (perhaps 1-sample) granularity.
+ If left unspecified (=0), the sender determines the chunk granularity.
+ * @param recover Try to silently recover lost streams that are recoverable (=those that that have a source_id set).
+ * In all other cases (recover is false or the stream is not recoverable) functions may throw a
+ * LostException if the stream's source is lost (e.g., due to an app or computer crash).
+ */
+ public StreamInlet(StreamInfo info, int max_buflen = 360, int max_chunklen = 0, bool recover = true, processing_options_t postproc_flags = processing_options_t.proc_none)
+ : base(dll.lsl_create_inlet(info.DangerousGetHandle(), max_buflen, max_chunklen, recover ? 1 : 0))
+ {
+ dll.lsl_set_postprocessing(obj, postproc_flags);
}
+ protected override void DestroyLSLObject(IntPtr obj)
+ {
+ dll.lsl_destroy_inlet(obj);
+ }
- // ===========================
- // === Continuous Resolver ===
- // ===========================
+ /**
+ * Retrieve the complete information of the given stream, including the extended description.
+ * Can be invoked at any time of the stream's lifetime.
+ * @param timeout Timeout of the operation (default: no timeout).
+ * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
+ */
+ public StreamInfo info(double timeout = LSL.FOREVER) { int ec = 0; IntPtr res = dll.lsl_get_fullinfo(obj, timeout, ref ec); LSL.check_error(ec); return new StreamInfo(res); }
- /**
- * A convenience class that resolves streams continuously in the background throughout
- * its lifetime and which can be queried at any time for the set of streams that are currently
- * visible on the network.
+ /**
+ * Subscribe to the data stream.
+ * All samples pushed in at the other end from this moment onwards will be queued and
+ * eventually be delivered in response to pull_sample() or pull_chunk() calls.
+ * Pulling a sample without some preceding open_stream is permitted (the stream will then be opened implicitly).
+ * @param timeout Optional timeout of the operation (default: no timeout).
+ * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
*/
+ public void open_stream(double timeout = LSL.FOREVER) { int ec = 0; dll.lsl_open_stream(obj, timeout, ref ec); LSL.check_error(ec); }
- public class ContinuousResolver
+ /**
+ * Drop the current data stream.
+ * All samples that are still buffered or in flight will be dropped and transmission
+ * and buffering of data for this inlet will be stopped. If an application stops being
+ * interested in data from a source (temporarily or not) but keeps the outlet alive,
+ * it should call close_stream() to not waste unnecessary system and network
+ * resources.
+ */
+ public void close_stream() { dll.lsl_close_stream(obj); }
+
+ /**
+ * Retrieve an estimated time correction offset for the given stream.
+ * The first call to this function takes several miliseconds until a reliable first estimate is obtained.
+ * Subsequent calls are instantaneous (and rely on periodic background updates).
+ * The precision of these estimates should be below 1 ms (empirically within +/-0.2 ms).
+ * @timeout Timeout to acquire the first time-correction estimate (default: no timeout).
+ * @return The time correction estimate. This is the number that needs to be added to a time stamp
+ * that was remotely generated via lsl_local_clock() to map it into the local clock domain of this machine.
+ * @throws TimeoutException (if the timeout expires), or LostException (if the stream source has been lost).
+ */
+ public double time_correction(double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_time_correction(obj, timeout, ref ec); LSL.check_error(ec); return res; }
+
+ // =======================================
+ // === Pulling a sample from the inlet ===
+ // =======================================
+
+ /**
+ * Pull a sample from the inlet and read it into an array of values.
+ * Handles type checking & conversion.
+ * @param sample An array to hold the resulting values.
+ * @param timeout The timeout for this operation, if any. Use 0.0 to make the function non-blocking.
+ * @return The capture time of the sample on the remote machine, or 0.0 if no new sample was available.
+ * To remap this time stamp to the local clock, add the value returned by .time_correction() to it.
+ * @throws LostException (if the stream source has been lost).
+ */
+ public double pull_sample(float[] sample, double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_f(obj, sample, sample.Length, timeout, ref ec); LSL.check_error(ec); return res; }
+ public double pull_sample(double[] sample, double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_d(obj, sample, sample.Length, timeout, ref ec); LSL.check_error(ec); return res; }
+ public double pull_sample(int[] sample, double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_i(obj, sample, sample.Length, timeout, ref ec); LSL.check_error(ec); return res; }
+ public double pull_sample(short[] sample, double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_s(obj, sample, sample.Length, timeout, ref ec); LSL.check_error(ec); return res; }
+ public double pull_sample(char[] sample, double timeout = LSL.FOREVER) { int ec = 0; double res = dll.lsl_pull_sample_c(obj, sample, sample.Length, timeout, ref ec); LSL.check_error(ec); return res; }
+ public double pull_sample(string[] sample, double timeout = LSL.FOREVER)
{
- /**
- * Construct a new continuous_resolver that resolves all streams on the network.
- * This is analogous to the functionality offered by the free function resolve_streams().
- * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
- * this is the time in seconds after which it is no longer reported by the resolver.
- */
- public ContinuousResolver() { obj = dll.lsl_create_continuous_resolver(5.0); }
- public ContinuousResolver(double forget_after) { obj = dll.lsl_create_continuous_resolver(forget_after); }
-
- /**
- * Construct a new continuous_resolver that resolves all streams with a specific value for a given property.
- * This is analogous to the functionality provided by the free function resolve_stream(prop,value).
- * @param prop The stream_info property that should have a specific value (e.g., "name", "type", "source_id", or "desc/manufaturer").
- * @param value The string value that the property should have (e.g., "EEG" as the type property).
- * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
- * this is the time in seconds after which it is no longer reported by the resolver.
- */
- public ContinuousResolver(string prop, string value) { obj = dll.lsl_create_continuous_resolver_byprop(prop, value, 5.0); }
- public ContinuousResolver(string prop, string value, double forget_after) { obj = dll.lsl_create_continuous_resolver_byprop(prop, value, forget_after); }
-
- /**
- * Construct a new continuous_resolver that resolves all streams that match a given XPath 1.0 predicate.
- * This is analogous to the functionality provided by the free function resolve_stream(pred).
- * @param pred The predicate string, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32"
- * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
- * this is the time in seconds after which it is no longer reported by the resolver.
- */
- public ContinuousResolver(string pred) { obj = dll.lsl_create_continuous_resolver_bypred(pred, 5.0); }
- public ContinuousResolver(string pred, double forget_after) { obj = dll.lsl_create_continuous_resolver_bypred(pred, forget_after); }
-
- ~ContinuousResolver() { Dispose(false); }
-
- /// Dispose of the object
- public void Dispose()
+ int ec = 0;
+ IntPtr[] tmp = new IntPtr[sample.Length];
+ double res = dll.lsl_pull_sample_str(obj, tmp, tmp.Length, timeout, ref ec); LSL.check_error(ec);
+ try
{
- Dispose(true);
- GC.SuppressFinalize(this);
+ for (int k = 0; k < tmp.Length; k++)
+ sample[k] = Marshal.PtrToStringAnsi(tmp[k]);
}
- private bool _disposed = false;
- protected virtual void Dispose(bool disposing)
+ finally
{
- if (_disposed)
- {
- return;
- }
-
- dll.lsl_destroy_continuous_resolver(obj);
- obj = IntPtr.Zero;
- _disposed = true;
+ for (int k = 0; k < tmp.Length; k++)
+ dll.lsl_destroy_string(tmp[k]);
}
+ return res;
+ }
+
+ // =================================================
+ // === Pulling a chunk of samples from the inlet ===
+ // =================================================
- /**
- * Obtain the set of currently present streams on the network (i.e. resolve result).
- * @return An array of matching stream info objects (excluding their meta-data), any of
- * which can subsequently be used to open an inlet.
- */
- public StreamInfo[] results()
+ /**
+ * Pull a chunk of data from the inlet.
+ * @param data_buffer A pre-allocated buffer where the channel data shall be stored.
+ * @param timestamp_buffer A pre-allocated buffer where time stamps shall be stored.
+ * @param timeout Optionally the timeout for this operation, if any. When the timeout expires, the function
+ * may return before the entire buffer is filled. The default value of 0.0 will retrieve only
+ * data available for immediate pickup.
+ * @return samples_written Number of samples written to the data and timestamp buffers.
+ * @throws LostException (if the stream source has been lost).
+ */
+ public int pull_chunk(float[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_f(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); LSL.check_error(ec); return (int)res / data_buffer.GetLength(1); }
+ public int pull_chunk(double[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_d(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); LSL.check_error(ec); return (int)res / data_buffer.GetLength(1); }
+ public int pull_chunk(int[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_i(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); LSL.check_error(ec); return (int)res / data_buffer.GetLength(1); }
+ public int pull_chunk(short[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_s(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); LSL.check_error(ec); return (int)res / data_buffer.GetLength(1); }
+ public int pull_chunk(char[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_c(obj, data_buffer, timestamp_buffer, (uint)data_buffer.Length, (uint)timestamp_buffer.Length, timeout, ref ec); LSL.check_error(ec); return (int)res / data_buffer.GetLength(1); }
+ public int pull_chunk(string[,] data_buffer, double[] timestamp_buffer, double timeout = 0.0)
+ {
+ int ec = 0;
+ IntPtr[,] tmp = new IntPtr[data_buffer.GetLength(0), data_buffer.GetLength(1)];
+ uint res = dll.lsl_pull_chunk_str(obj, tmp, timestamp_buffer, (uint)tmp.Length, (uint)timestamp_buffer.Length, timeout, ref ec);
+ LSL.check_error(ec);
+ try
{
- IntPtr[] buf = new IntPtr[1024];
- int num = dll.lsl_resolver_results(obj, buf, (uint)buf.Length);
- StreamInfo[] res = new StreamInfo[num];
- for (int k = 0; k < num; k++)
- res[k] = new StreamInfo(buf[k]);
- return res;
+ for (int s = 0; s < tmp.GetLength(0); s++)
+ for (int c = 0; c < tmp.GetLength(1); c++)
+ data_buffer[s, c] = Marshal.PtrToStringAnsi(tmp[s, c]);
}
-
- private IntPtr obj;
+ finally
+ {
+ for (int s = 0; s < tmp.GetLength(0); s++)
+ for (int c = 0; c < tmp.GetLength(1); c++)
+ dll.lsl_destroy_string(tmp[s, c]);
+ }
+ return (int)res / data_buffer.GetLength(1);
}
- // =======================
- // === Exception Types ===
- // =======================
+ /**
+ * Query whether samples are currently available for immediate pickup.
+ * Note that it is not a good idea to use samples_available() to determine whether
+ * a pull_*() call would block: to be sure, set the pull timeout to 0.0 or an acceptably
+ * low value. If the underlying implementation supports it, the value will be the number of
+ * samples available (otherwise it will be 1 or 0).
+ */
+ public int samples_available() { return (int)dll.lsl_samples_available(obj); }
/**
- * Exception class that indicates that a stream inlet's source has been irrecoverably lost.
- */
- public class LostException : System.Exception
- {
- public LostException() { }
- public LostException(string message) { }
- public LostException(string message, System.Exception inner) { }
- protected LostException(System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context)
- { }
- }
+ * Query whether the clock was potentially reset since the last call to was_clock_reset().
+ * This is a rarely-used function that is only useful to applications that combine multiple time_correction
+ * values to estimate precise clock drift; it allows to tolerate cases where the source machine was
+ * hot-swapped or restarted in between two measurements.
+ */
+ public bool was_clock_reset() { return (int)dll.lsl_was_clock_reset(obj) != 0; }
+ }
+
+
+ // =====================
+ // ==== XML Element ====
+ // =====================
+
+ /**
+ * A lightweight XML element tree; models the .desc() field of stream_info.
+ * Has a name and can have multiple named children or have text content as value; attributes are omitted.
+ * Insider note: The interface is modeled after a subset of pugixml's node type and is compatible with it.
+ * See also http://pugixml.googlecode.com/svn/tags/latest/docs/manual/access.html for additional documentation.
+ */
+ public struct XMLElement
+ {
+ public XMLElement(IntPtr handle) { obj = handle; }
+
+ // === Tree Navigation ===
+
+ /// Get the first child of the element.
+ public XMLElement first_child() { return new XMLElement(dll.lsl_first_child(obj)); }
+
+ /// Get the last child of the element.
+ public XMLElement last_child() { return new XMLElement(dll.lsl_last_child(obj)); }
+
+ /// Get the next sibling in the children list of the parent node.
+ public XMLElement next_sibling() { return new XMLElement(dll.lsl_next_sibling(obj)); }
+
+ /// Get the previous sibling in the children list of the parent node.
+ public XMLElement previous_sibling() { return new XMLElement(dll.lsl_previous_sibling(obj)); }
+
+ /// Get the parent node.
+ public XMLElement parent() { return new XMLElement(dll.lsl_parent(obj)); }
+
+
+ // === Tree Navigation by Name ===
+
+ /// Get a child with a specified name.
+ public XMLElement child(string name) { return new XMLElement(dll.lsl_child(obj, name)); }
+
+ /// Get the next sibling with the specified name.
+ public XMLElement next_sibling(string name) { return new XMLElement(dll.lsl_next_sibling_n(obj, name)); }
+
+ /// Get the previous sibling with the specified name.
+ public XMLElement previous_sibling(string name) { return new XMLElement(dll.lsl_previous_sibling_n(obj, name)); }
+
+
+ // === Content Queries ===
+
+ /// Whether this node is empty.
+ public bool empty() { return dll.lsl_empty(obj) != 0; }
+
+ /// Whether this is a text body (instead of an XML element). True both for plain char data and CData.
+ public bool is_text() { return dll.lsl_is_text(obj) != 0; }
+
+ /// Name of the element.
+ public string name() { return Marshal.PtrToStringAnsi(dll.lsl_name(obj)); }
+
+ /// Value of the element.
+ public string value() { return Marshal.PtrToStringAnsi(dll.lsl_value(obj)); }
+
+ /// Get child value (value of the first child that is text).
+ public string child_value() { return Marshal.PtrToStringAnsi(dll.lsl_child_value(obj)); }
+
+ /// Get child value of a child with a specified name.
+ public string child_value(string name) { return Marshal.PtrToStringAnsi(dll.lsl_child_value_n(obj, name)); }
+
+
+ // === Modification ===
/**
- * Exception class that indicates that an internal error has occurred inside liblsl.
- */
- public class InternalException : System.Exception
+ * Append a child node with a given name, which has a (nameless) plain-text child with the given text value.
+ */
+ public XMLElement append_child_value(string name, string value) { return new XMLElement(dll.lsl_append_child_value(obj, name, value)); }
+
+ /**
+ * Prepend a child node with a given name, which has a (nameless) plain-text child with the given text value.
+ */
+ public XMLElement prepend_child_value(string name, string value) { return new XMLElement(dll.lsl_prepend_child_value(obj, name, value)); }
+
+ /**
+ * Set the text value of the (nameless) plain-text child of a named child node.
+ */
+ public bool set_child_value(string name, string value) { return dll.lsl_set_child_value(obj, name, value) != 0; }
+
+ /**
+ * Set the element's name.
+ * @return False if the node is empty.
+ */
+ public bool set_name(string rhs) { return dll.lsl_set_name(obj, rhs) != 0; }
+
+ /**
+ * Set the element's value.
+ * @return False if the node is empty.
+ */
+ public bool set_value(string rhs) { return dll.lsl_set_value(obj, rhs) != 0; }
+
+ /// Append a child element with the specified name.
+ public XMLElement append_child(string name) { return new XMLElement(dll.lsl_append_child(obj, name)); }
+
+ /// Prepend a child element with the specified name.
+ public XMLElement prepend_child(string name) { return new XMLElement(dll.lsl_prepend_child(obj, name)); }
+
+ /// Append a copy of the specified element as a child.
+ public XMLElement append_copy(XMLElement e) { return new XMLElement(dll.lsl_append_copy(obj, e.obj)); }
+
+ /// Prepend a child element with the specified name.
+ public XMLElement prepend_copy(XMLElement e) { return new XMLElement(dll.lsl_prepend_copy(obj, e.obj)); }
+
+ /// Remove a child element with the specified name.
+ public void remove_child(string name) { dll.lsl_remove_child_n(obj, name); }
+
+ /// Remove a specified child element.
+ public void remove_child(XMLElement e) { dll.lsl_remove_child(obj, e.obj); }
+
+ readonly IntPtr obj;
+ }
+
+
+ // ===========================
+ // === Continuous Resolver ===
+ // ===========================
+
+ /**
+ * A convenience class that resolves streams continuously in the background throughout
+ * its lifetime and which can be queried at any time for the set of streams that are currently
+ * visible on the network.
+ */
+
+ public class ContinuousResolver : LSLObject
+ {
+ /**
+ * Construct a new continuous_resolver that resolves all streams on the network.
+ * This is analogous to the functionality offered by the free function resolve_streams().
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
+ * this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ public ContinuousResolver(double forget_after = 5.0)
+ : base(dll.lsl_create_continuous_resolver(forget_after)) { }
+
+ /**
+ * Construct a new continuous_resolver that resolves all streams with a specific value for a given property.
+ * This is analogous to the functionality provided by the free function resolve_stream(prop,value).
+ * @param prop The stream_info property that should have a specific value (e.g., "name", "type", "source_id", or "desc/manufaturer").
+ * @param value The string value that the property should have (e.g., "EEG" as the type property).
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
+ * this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ public ContinuousResolver(string prop, string value, double forget_after = 5.0)
+ : base(dll.lsl_create_continuous_resolver_byprop(prop, value, forget_after)) { }
+
+ /**
+ * Construct a new continuous_resolver that resolves all streams that match a given XPath 1.0 predicate.
+ * This is analogous to the functionality provided by the free function resolve_stream(pred).
+ * @param pred The predicate string, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32"
+ * @param forget_after When a stream is no longer visible on the network (e.g., because it was shut down),
+ * this is the time in seconds after which it is no longer reported by the resolver.
+ */
+ public ContinuousResolver(string pred, double forget_after = 5.0)
+ : base(dll.lsl_create_continuous_resolver_bypred(pred, forget_after)) { }
+
+
+ /**
+ * Obtain the set of currently present streams on the network (i.e. resolve result).
+ * @return An array of matching stream info objects (excluding their meta-data), any of
+ * which can subsequently be used to open an inlet.
+ */
+ public StreamInfo[] results()
{
- public InternalException() { }
- public InternalException(string message) { }
- public InternalException(string message, System.Exception inner) { }
- protected InternalException(System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context)
- { }
+ IntPtr[] buf = new IntPtr[1024];
+ int num = dll.lsl_resolver_results(obj, buf, (uint)buf.Length);
+ StreamInfo[] res = new StreamInfo[num];
+ for (int k = 0; k < num; k++)
+ res[k] = new StreamInfo(buf[k]);
+ return res;
}
- /**
- * Check an error condition and throw an exception if appropriate.
- */
- public static void check_error(int ec)
+ protected override void DestroyLSLObject(IntPtr obj)
{
- if (ec < 0)
- switch (ec)
- {
- case -1: throw new TimeoutException("The operation failed due to a timeout.");
- case -2: throw new LostException("The stream has been lost.");
- case -3: throw new ArgumentException("An argument was incorrectly specified (e.g., wrong format or wrong length).");
- case -4: throw new InternalException("An internal internal error has occurred.");
- default: throw new Exception("An unknown error has occurred.");
- }
+ dll.lsl_destroy_continuous_resolver(obj);
}
+ }
+ #region Exception Types
+ /**
+ * Exception class that indicates that a stream inlet's source has been irrecoverably lost.
+ */
+ public class LostException : System.Exception
+ {
+ public LostException(string message = "", System.Exception inner = null) { }
+ protected LostException(System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context)
+ { }
+ }
+
+ /**
+ * Exception class that indicates that an internal error has occurred inside liblsl.
+ */
+ public class InternalException : System.Exception
+ {
+ public InternalException(string message = "", System.Exception inner = null) { }
+ protected InternalException(System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context)
+ { }
+ }
+ #endregion
- // === Internal: C library function definitions. ===
- class dll
- {
- // Name of the binary to include -- replace this if the native library has a differentname
- const string libname = "lsl";
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_protocol_version();
+ #region Internal: C library function definitions
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_library_version();
+ class dll
+ {
+ // Name of the binary to include -- replace this if the native library has a differentname
+ const string libname = "lsl";
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_local_clock();
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_protocol_version();
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_streaminfo(string name, string type, int channel_count, double nominal_srate, channel_format_t channel_format, string source_id);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_library_version();
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_destroy_streaminfo(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_local_clock();
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_name(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_streaminfo(string name, string type, int channel_count, double nominal_srate, channel_format_t channel_format, string source_id);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_type(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_destroy_streaminfo(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_get_channel_count(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_name(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_get_nominal_srate(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_type(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern channel_format_t lsl_get_channel_format(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_get_channel_count(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_source_id(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_get_nominal_srate(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_get_version(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern channel_format_t lsl_get_channel_format(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_get_created_at(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_source_id(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_uid(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_get_version(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_session_id(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_get_created_at(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_hostname(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_uid(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_desc(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_session_id(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_xml(IntPtr info);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_hostname(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_outlet(IntPtr info, int chunk_size, int max_buffered);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_desc(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_destroy_outlet(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_xml(IntPtr info);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_ftp(IntPtr obj, float[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_outlet(IntPtr info, int chunk_size, int max_buffered);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_dtp(IntPtr obj, double[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_destroy_outlet(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_itp(IntPtr obj, int[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_ftp(IntPtr obj, float[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_stp(IntPtr obj, short[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_dtp(IntPtr obj, double[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_ctp(IntPtr obj, char[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_itp(IntPtr obj, int[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_strtp(IntPtr obj, string[] data, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_stp(IntPtr obj, short[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_sample_buftp(IntPtr obj, char[][] data, uint[] lengths, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_ctp(IntPtr obj, char[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_ftp(IntPtr obj, float[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_strtp(IntPtr obj, string[] data, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_ftnp(IntPtr obj, float[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_sample_buftp(IntPtr obj, char[][] data, uint[] lengths, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_dtp(IntPtr obj, double[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_ftp(IntPtr obj, float[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_dtnp(IntPtr obj, double[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_ftnp(IntPtr obj, float[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_itp(IntPtr obj, int[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_dtp(IntPtr obj, double[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_itnp(IntPtr obj, int[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_dtnp(IntPtr obj, double[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_stp(IntPtr obj, short[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_itp(IntPtr obj, int[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_stnp(IntPtr obj, short[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_itnp(IntPtr obj, int[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_ctp(IntPtr obj, char[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_stp(IntPtr obj, short[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_ctnp(IntPtr obj, char[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_stnp(IntPtr obj, short[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_strtp(IntPtr obj, string[,] data, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_ctp(IntPtr obj, char[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_strtnp(IntPtr obj, string[,] data, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_ctnp(IntPtr obj, char[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_buftp(IntPtr obj, char[][] data, uint[] lengths, uint data_elements, double timestamp, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_strtp(IntPtr obj, string[,] data, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_push_chunk_buftnp(IntPtr obj, char[][] data, uint[] lengths, uint data_elements, double[] timestamps, int pushthrough);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_strtnp(IntPtr obj, string[,] data, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_have_consumers(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_buftp(IntPtr obj, char[][] data, uint[] lengths, uint data_elements, double timestamp, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_wait_for_consumers(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_push_chunk_buftnp(IntPtr obj, char[][] data, uint[] lengths, uint data_elements, double[] timestamps, int pushthrough);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_info(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_have_consumers(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_resolve_all(IntPtr[] buffer, uint buffer_elements, double wait_time);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_wait_for_consumers(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_resolve_byprop(IntPtr[] buffer, uint buffer_elements, string prop, string value, int minimum, double wait_time);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_info(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_resolve_bypred(IntPtr[] buffer, uint buffer_elements, string pred, int minimum, double wait_time);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_resolve_all(IntPtr[] buffer, uint buffer_elements, double wait_time);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_inlet(IntPtr info, int max_buflen, int max_chunklen, int recover);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_resolve_byprop(IntPtr[] buffer, uint buffer_elements, string prop, string value, int minimum, double wait_time);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_destroy_inlet(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_resolve_bypred(IntPtr[] buffer, uint buffer_elements, string pred, int minimum, double wait_time);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_get_fullinfo(IntPtr obj, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_inlet(IntPtr info, int max_buflen, int max_chunklen, int recover);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_open_stream(IntPtr obj, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_destroy_inlet(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_close_stream(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_get_fullinfo(IntPtr obj, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_time_correction(IntPtr obj, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_open_stream(IntPtr obj, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_set_postprocessing(IntPtr obj, processing_options_t flags);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_close_stream(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_f(IntPtr obj, float[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_time_correction(IntPtr obj, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_d(IntPtr obj, double[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_set_postprocessing(IntPtr obj, processing_options_t flags);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_i(IntPtr obj, int[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_f(IntPtr obj, float[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_s(IntPtr obj, short[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_d(IntPtr obj, double[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_c(IntPtr obj, char[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_i(IntPtr obj, int[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_str(IntPtr obj, IntPtr[] buffer, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_s(IntPtr obj, short[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern double lsl_pull_sample_buf(IntPtr obj, char[][] buffer, uint[] buffer_lengths, int buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_c(IntPtr obj, char[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_destroy_string(IntPtr str);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_str(IntPtr obj, IntPtr[] buffer, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_f(IntPtr obj, float[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern double lsl_pull_sample_buf(IntPtr obj, char[][] buffer, uint[] buffer_lengths, int buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_d(IntPtr obj, double[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_destroy_string(IntPtr str);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_i(IntPtr obj, int[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_f(IntPtr obj, float[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_s(IntPtr obj, short[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_d(IntPtr obj, double[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_c(IntPtr obj, char[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_i(IntPtr obj, int[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_str(IntPtr obj, IntPtr[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_s(IntPtr obj, short[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_pull_chunk_buf(IntPtr obj, char[][,] data_buffer, uint[,] lengths_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_c(IntPtr obj, char[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_samples_available(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_str(IntPtr obj, IntPtr[,] data_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern uint lsl_was_clock_reset(IntPtr obj);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_pull_chunk_buf(IntPtr obj, char[][,] data_buffer, uint[,] lengths_buffer, double[] timestamp_buffer, uint data_buffer_elements, uint timestamp_buffer_elements, double timeout, ref int ec);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_first_child(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_samples_available(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_last_child(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern uint lsl_was_clock_reset(IntPtr obj);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_next_sibling(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_first_child(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_previous_sibling(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_last_child(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_parent(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_next_sibling(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_child(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_previous_sibling(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_next_sibling_n(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_parent(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_previous_sibling_n(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_child(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_empty(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_next_sibling_n(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_is_text(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_previous_sibling_n(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_name(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_empty(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_value(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_is_text(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_child_value(IntPtr e);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_name(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_child_value_n(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_value(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_append_child_value(IntPtr e, string name, string value);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_child_value(IntPtr e);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_prepend_child_value(IntPtr e, string name, string value);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_child_value_n(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_set_child_value(IntPtr e, string name, string value);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_append_child_value(IntPtr e, string name, string value);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_set_name(IntPtr e, string rhs);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_prepend_child_value(IntPtr e, string name, string value);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_set_value(IntPtr e, string rhs);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_set_child_value(IntPtr e, string name, string value);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_append_child(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_set_name(IntPtr e, string rhs);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_prepend_child(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_set_value(IntPtr e, string rhs);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_append_copy(IntPtr e, IntPtr e2);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_append_child(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_prepend_copy(IntPtr e, IntPtr e2);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_prepend_child(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_remove_child_n(IntPtr e, string name);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_append_copy(IntPtr e, IntPtr e2);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_remove_child(IntPtr e, IntPtr e2);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_prepend_copy(IntPtr e, IntPtr e2);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_continuous_resolver(double forget_after);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_remove_child_n(IntPtr e, string name);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_continuous_resolver_byprop(string prop, string value, double forget_after);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_remove_child(IntPtr e, IntPtr e2);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern IntPtr lsl_create_continuous_resolver_bypred(string pred, double forget_after);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_continuous_resolver(double forget_after);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern int lsl_resolver_results(IntPtr obj, IntPtr[] buffer, uint buffer_elements);
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_continuous_resolver_byprop(string prop, string value, double forget_after);
- [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
- public static extern void lsl_destroy_continuous_resolver(IntPtr obj);
- }
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern IntPtr lsl_create_continuous_resolver_bypred(string pred, double forget_after);
+
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern int lsl_resolver_results(IntPtr obj, IntPtr[] buffer, uint buffer_elements);
+
+ [DllImport(libname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]
+ public static extern void lsl_destroy_continuous_resolver(IntPtr obj);
}
+ #endregion
}
diff --git a/examples/Directory.Build.props b/examples/Directory.Build.props
new file mode 100644
index 0000000..7a68623
--- /dev/null
+++ b/examples/Directory.Build.props
@@ -0,0 +1,6 @@
+
+
+
+ 8.0
+
+
\ No newline at end of file
diff --git a/examples/HandleMetaData/HandleMetaData.cs b/examples/HandleMetaData/HandleMetaData.cs
index 234f6d3..c306af8 100644
--- a/examples/HandleMetaData/HandleMetaData.cs
+++ b/examples/HandleMetaData/HandleMetaData.cs
@@ -1,45 +1,51 @@
using System;
-using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class HandleMetaData
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
+ {
+ using StreamInfo inf_ = new StreamInfo("Test", "EEG", 8, 100, channel_format_t.cf_double64, "test1234");
+ Console.Out.WriteLine("Test");
+ }
// create a new StreamInfo and declare some meta-data (in accordance with XDF format)
- liblsl.StreamInfo info = new liblsl.StreamInfo("MetaTester","EEG",8,100,liblsl.channel_format_t.cf_float32,"myuid323457");
- liblsl.XMLElement chns = info.desc().append_child("channels");
- String[] labels = {"C3","C4","Cz","FPz","POz","CPz","O1","O2"};
- for (int k=0;k
-
-
-
- HandleMetaData
- Exe
- netcoreapp2.0
+ net5.0
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/LSLExamples.csproj b/examples/LSLExamples.csproj
new file mode 100644
index 0000000..912f39e
--- /dev/null
+++ b/examples/LSLExamples.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netcoreapp5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+ LSLExamples.EntryPoint
+
+
+
+
+
diff --git a/examples/Main.cs b/examples/Main.cs
new file mode 100644
index 0000000..3f17f3e
--- /dev/null
+++ b/examples/Main.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace LSLExamples
+{
+ static class EntryPoint
+ {
+ public static void Main(string[] args) {
+ var examples = Assembly.GetExecutingAssembly().GetTypes()
+ .Where(t => t.Namespace =="LSLExamples").ToDictionary(e=>e.Name, e=>e);
+
+ var WrapperVersion = Assembly.GetAssembly(typeof(LSL.LSL)).GetName().Version.ToString();
+ Console.Out.Write("Wrapper version: ");
+ Console.Out.WriteLine(WrapperVersion);
+ Console.Out.Write("liblsl version: ");
+ Console.Out.WriteLine(LSL.LSL.library_version());
+ if (args.Length < 1 || !examples.ContainsKey(args[0])) {
+ Console.Out.WriteLine("\nNot enough arguments. Valid examples:");
+ foreach(var name in examples.Keys) Console.Out.WriteLine(name);
+ return;
+ }
+ var method = examples[args[0]].GetMethod("Main", BindingFlags.Public|BindingFlags.Static);
+ Console.Out.WriteLine(method);
+ method.Invoke(null, new object[]{ args});
+ }
+ }
+}
+
diff --git a/examples/ReceiveData/ReceiveData.cs b/examples/ReceiveData/ReceiveData.cs
index fe61560..96d1ed5 100644
--- a/examples/ReceiveData/ReceiveData.cs
+++ b/examples/ReceiveData/ReceiveData.cs
@@ -1,31 +1,28 @@
-using System;
-using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class ReceiveData
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
// wait until an EEG stream shows up
- liblsl.StreamInfo[] results = liblsl.resolve_stream("type", "EEG");
+ StreamInfo[] results = LSL.LSL.resolve_stream("type", "EEG");
// open an inlet and print some interesting info about the stream (meta-data, etc.)
- liblsl.StreamInlet inlet = new liblsl.StreamInlet(results[0]);
+ using StreamInlet inlet = new StreamInlet(results[0]);
+ results.DisposeArray();
System.Console.Write(inlet.info().as_xml());
// read samples
float[] sample = new float[8];
- while (true)
+ while (!System.Console.KeyAvailable)
{
inlet.pull_sample(sample);
foreach (float f in sample)
- System.Console.Write("\t{0}",f);
+ System.Console.Write("\t{0}", f);
System.Console.WriteLine();
}
-
- System.Console.ReadKey();
}
}
}
diff --git a/examples/ReceiveData/ReceiveData.csproj b/examples/ReceiveData/ReceiveData.csproj
index 9466489..e5668bc 100644
--- a/examples/ReceiveData/ReceiveData.csproj
+++ b/examples/ReceiveData/ReceiveData.csproj
@@ -1,10 +1,12 @@
-
-
-
-
+
- ReceiveData
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/ReceiveDataInChunks/ReceiveDataInChunks.cs b/examples/ReceiveDataInChunks/ReceiveDataInChunks.cs
index 00626d1..2f8695b 100644
--- a/examples/ReceiveDataInChunks/ReceiveDataInChunks.cs
+++ b/examples/ReceiveDataInChunks/ReceiveDataInChunks.cs
@@ -1,30 +1,30 @@
using System;
-using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class ReceiveDataInChunks
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
// wait until an EEG stream shows up
- liblsl.StreamInfo[] results = liblsl.resolve_stream("type", "EEG");
+ StreamInfo[] results = LSL.LSL.resolve_stream("type", "EEG");
// open an inlet, with post-processing enabled, and print meta-data
// Note: The use of post-processing makes it impossible to recover
// the original timestamps and is not recommended for applications
// that store data to disk.
- liblsl.StreamInlet inlet = new liblsl.StreamInlet(results[0],
- postproc_flags: liblsl.processing_options_t.proc_ALL);
+ using StreamInlet inlet = new StreamInlet(results[0],
+ postproc_flags: processing_options_t.proc_ALL);
+ results.DisposeArray();
System.Console.Write(inlet.info().as_xml());
// read samples
float[,] buffer = new float[512, 8];
double[] timestamps = new double[512];
- while (true)
+ while (!Console.KeyAvailable)
{
- int num = inlet.pull_chunk(buffer,timestamps);
+ int num = inlet.pull_chunk(buffer, timestamps);
for (int s = 0; s < num; s++)
{
for (int c = 0; c < 8; c++)
diff --git a/examples/ReceiveDataInChunks/ReceiveDataInChunks.csproj b/examples/ReceiveDataInChunks/ReceiveDataInChunks.csproj
index 4aba4fa..e5668bc 100644
--- a/examples/ReceiveDataInChunks/ReceiveDataInChunks.csproj
+++ b/examples/ReceiveDataInChunks/ReceiveDataInChunks.csproj
@@ -1,10 +1,12 @@
-
-
-
- ReceiveDataInChunks
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/ReceiveStringMarkers/ReceiveStringMarkers.cs b/examples/ReceiveStringMarkers/ReceiveStringMarkers.cs
index f4acec5..78baada 100644
--- a/examples/ReceiveStringMarkers/ReceiveStringMarkers.cs
+++ b/examples/ReceiveStringMarkers/ReceiveStringMarkers.cs
@@ -1,26 +1,26 @@
using System;
-using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class ReceiveStringMarkers
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
// wait until an EEG stream shows up
- liblsl.StreamInfo[] results = liblsl.resolve_stream("type", "Markers");
+ StreamInfo[] results = LSL.LSL.resolve_stream("type", "Markers");
// open an inlet and print meta-data
- liblsl.StreamInlet inlet = new liblsl.StreamInlet(results[0]);
- System.Console.Write(inlet.info().as_xml());
+ using StreamInlet inlet = new StreamInlet(results[0]);
+ results.DisposeArray();
+ Console.Write(inlet.info().as_xml());
// read samples
string[] sample = new string[1];
- while (true)
+ while (!Console.KeyAvailable)
{
inlet.pull_sample(sample);
- System.Console.WriteLine(sample[0]);
+ Console.WriteLine(sample[0]);
}
}
}
diff --git a/examples/ReceiveStringMarkers/ReceiveStringMarkers.csproj b/examples/ReceiveStringMarkers/ReceiveStringMarkers.csproj
index f6aee65..e5668bc 100644
--- a/examples/ReceiveStringMarkers/ReceiveStringMarkers.csproj
+++ b/examples/ReceiveStringMarkers/ReceiveStringMarkers.csproj
@@ -1,10 +1,12 @@
-
-
-
- ReceiveStringMarkers
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/SendData/SendData.cs b/examples/SendData/SendData.cs
index bcb390d..2a98d35 100644
--- a/examples/SendData/SendData.cs
+++ b/examples/SendData/SendData.cs
@@ -2,28 +2,26 @@
using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class SendData
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
Random rnd = new Random();
// create stream info and outlet
- liblsl.StreamInfo info = new liblsl.StreamInfo("TestCSharp", "EEG", 8, 100, liblsl.channel_format_t.cf_float32, "sddsfsdf");
- liblsl.StreamOutlet outlet = new liblsl.StreamOutlet(info);
+ using StreamInfo info = new StreamInfo("TestCSharp", "EEG", 8, 100, channel_format_t.cf_float32, "sddsfsdf");
+ using StreamOutlet outlet = new StreamOutlet(info);
float[] data = new float[8];
- while (true)
+ while (!Console.KeyAvailable)
{
// generate random data and send it
for (int k = 0; k < data.Length; k++)
data[k] = rnd.Next(-100, 100);
outlet.push_sample(data);
- System.Threading.Thread.Sleep(10);
+ Thread.Sleep(10);
}
-
- System.Console.ReadKey();
}
}
}
diff --git a/examples/SendData/SendData.csproj b/examples/SendData/SendData.csproj
index a33dab2..e5668bc 100644
--- a/examples/SendData/SendData.csproj
+++ b/examples/SendData/SendData.csproj
@@ -1,10 +1,12 @@
-
-
-
- SendData
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/SendDataInChunks/SendDataInChunks.cs b/examples/SendDataInChunks/SendDataInChunks.cs
index a95e995..32821d4 100644
--- a/examples/SendDataInChunks/SendDataInChunks.cs
+++ b/examples/SendDataInChunks/SendDataInChunks.cs
@@ -2,26 +2,26 @@
using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class SendDataInChunks
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
Random rnd = new Random();
- // create stream info and outlet
- liblsl.StreamInfo info = new liblsl.StreamInfo("TestCSharp", "EEG", 8, 100, liblsl.channel_format_t.cf_float32, "sddsfsdf");
- liblsl.StreamOutlet outlet = new liblsl.StreamOutlet(info);
+ // create stream info and outlet
+ using StreamInfo info = new StreamInfo("TestCSharp", "EEG", 8, 100, channel_format_t.cf_float32, "sddsfsdf");
+ using StreamOutlet outlet = new StreamOutlet(info);
- // send data in chunks of 10 samples and 8 channels
+ // send data in chunks of 10 samples and 8 channels
float[,] data = new float[10, 8];
- while (true)
+ while (!Console.KeyAvailable)
{
for (int s = 0; s < 10; s++)
for (int c = 0; c < 8; c++)
data[s, c] = rnd.Next(-100, 100);
outlet.push_chunk(data);
- System.Threading.Thread.Sleep(100);
+ Thread.Sleep(100);
}
}
}
diff --git a/examples/SendDataInChunks/SendDataInChunks.csproj b/examples/SendDataInChunks/SendDataInChunks.csproj
index 0589378..e5668bc 100644
--- a/examples/SendDataInChunks/SendDataInChunks.csproj
+++ b/examples/SendDataInChunks/SendDataInChunks.csproj
@@ -1,10 +1,12 @@
-
-
-
- SendDataInChunks
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/examples/SendStringMarkers/SendStringMarkers.cs b/examples/SendStringMarkers/SendStringMarkers.cs
index 5d3c783..c4e431e 100644
--- a/examples/SendStringMarkers/SendStringMarkers.cs
+++ b/examples/SendStringMarkers/SendStringMarkers.cs
@@ -2,25 +2,26 @@
using System.Threading;
using LSL;
-namespace ConsoleApplication1
+namespace LSLExamples
{
- class Program
+ static class SendStringMarkers
{
- static void Main(string[] args)
+ public static void Main(string[] args)
{
// create stream info and outlet
- liblsl.StreamInfo inf = new liblsl.StreamInfo("Test1", "Markers", 1, 0, liblsl.channel_format_t.cf_string, "giu4569");
- liblsl.StreamOutlet outl = new liblsl.StreamOutlet(inf);
+ using StreamInfo inf = new StreamInfo("Test1", "Markers", 1, 0, channel_format_t.cf_string, "giu4569");
+ using StreamOutlet outl = new StreamOutlet(inf);
Random rnd = new Random();
string[] strings = new string[] { "Test", "ABC", "123" };
string[] sample = new string[1];
- for (int k = 0; ; k++)
+ for (int k = 0; !Console.KeyAvailable; k++)
{
// send a marker and wait for a random interval
sample[0] = strings[k % 3];
outl.push_sample(sample);
- System.Threading.Thread.Sleep(rnd.Next(1000));
+ Console.Out.WriteLine(sample[0]);
+ Thread.Sleep(rnd.Next(1000));
}
}
}
diff --git a/examples/SendStringMarkers/SendStringMarkers.csproj b/examples/SendStringMarkers/SendStringMarkers.csproj
index 2d9aea3..e5668bc 100644
--- a/examples/SendStringMarkers/SendStringMarkers.csproj
+++ b/examples/SendStringMarkers/SendStringMarkers.csproj
@@ -1,10 +1,12 @@
-
-
-
- SendStringMarkers
- Exe
- netcoreapp2.0
+ net5.0
+ Labstreaminglayer C# examples
+ 1.14
+ 8.0
+ Exe
+
+
+
diff --git a/liblsl.csproj b/liblsl.csproj
index 65a4786..9e7f251 100644
--- a/liblsl.csproj
+++ b/liblsl.csproj
@@ -4,7 +4,7 @@
netstandard2.0
LSL
Labstreaminglayer C# bindings
- 1.14
+ 2.0
$(DefaultItemExcludes);examples/**
lsl_csharp