diff --git a/Demos/LSLTransformDemoOutlet.cs b/Demos/LSLTransformDemoOutlet.cs index 5ba59c3cbf5ac6371ec7e2cb97cd7bac55a8da30..cdb26e1ef4a05fb7c4ec2a4b308b18c64a335071 100644 --- a/Demos/LSLTransformDemoOutlet.cs +++ b/Demos/LSLTransformDemoOutlet.cs @@ -20,7 +20,7 @@ namespace LSL4Unity.Demos private double _dataRate; public double GetDataRate() { return _dataRate; } - public bool HasConsumer() { return _outlet != null && _outlet.have_consumers(); } + public bool HasConsumer() { return _outlet != null && _outlet.HaveConsumers(); } public string StreamName = "BeMoBI.Unity.Orientation.<Add_a_entity_id_here>"; public string StreamType = "Unity.Quaternion"; @@ -34,12 +34,9 @@ namespace LSL4Unity.Demos { // initialize the array once _currentSample = new float[ChannelCount]; - - _dataRate = LSLUtils.GetSamplingRateFor(Sampling); - - _streamInfo = new liblsl.StreamInfo(StreamName, StreamType, ChannelCount, _dataRate, liblsl.channel_format_t.cf_float32, UNIQUE_SOURCE_ID); - - _outlet = new liblsl.StreamOutlet(_streamInfo); + _dataRate = LSLUtils.GetSamplingRateFor(Sampling); + _streamInfo = new liblsl.StreamInfo(StreamName, StreamType, ChannelCount, _dataRate, liblsl.channel_format_t.cf_float32, UNIQUE_SOURCE_ID); + _outlet = new liblsl.StreamOutlet(_streamInfo); } private void PushSample() @@ -53,7 +50,7 @@ namespace LSL4Unity.Demos _currentSample[2] = rotation.z; _currentSample[3] = rotation.w; - _outlet.push_sample(_currentSample, liblsl.local_clock()); + _outlet.PushSample(_currentSample, liblsl.LocalClock()); } private void FixedUpdate() diff --git a/Demos/RandomMarker.cs b/Demos/RandomMarker.cs index 4f7d9d75da31474f24052427734dc0eb9df07b6d..344917171c28c4c8c8852dedaaf2e9e81c480cad 100644 --- a/Demos/RandomMarker.cs +++ b/Demos/RandomMarker.cs @@ -3,8 +3,6 @@ using LSL4Unity.Scripts; using UnityEngine; using UnityEngine.Assertions; -// Don't forget the Namespace import - namespace LSL4Unity.Demos { public class RandomMarker : MonoBehaviour diff --git a/Editor/LSLEditorWindow.cs b/Editor/LSLEditorWindow.cs index d1b2722e11367a8920141a396f428095c28e287a..17f7ae6e23d4babdbaa1ef3dbf5968c7a6296a1e 100644 --- a/Editor/LSLEditorWindow.cs +++ b/Editor/LSLEditorWindow.cs @@ -25,8 +25,8 @@ namespace LSL4Unity.Editor { _resolver = new liblsl.ContinuousResolver(); - var libVersion = liblsl.library_version(); - var protocolVersion = liblsl.protocol_version(); + var libVersion = liblsl.LibraryVersion(); + var protocolVersion = liblsl.ProtocolVersion(); var libMajor = libVersion / 100; var libMinor = libVersion % 100; @@ -89,7 +89,7 @@ namespace LSL4Unity.Editor if (_streamInfos.Length == 0) { _streamLookUpResult = NO_STREAMS_FOUND; } else { - foreach (var item in _streamInfos) { _listNamesOfStreams.Add($"{item.Name()} {item.Type()} {item.Hostname()} {item.nominal_srate()}"); } + foreach (var item in _streamInfos) { _listNamesOfStreams.Add($"{item.Name()} {item.Type()} {item.Hostname()} {item.Sampling()}"); } _streamLookUpResult = _listNamesOfStreams.Count + N_STREAMS_FOUND; } } diff --git a/LSL.cs b/LSL.cs index ad7d3e4290e3e25ac40295e1664f7e0a09c5a010..323f40a01de1bcfa1f1291014a67bbaa7c5d17fd 100644 --- a/LSL.cs +++ b/LSL.cs @@ -19,137 +19,126 @@ namespace LSL4Unity { public class liblsl { - /** - * Constant to indicate that a stream has variable sampling rate. - */ + /// <summary> Constant to indicate that a stream has variable sampling rate. </summary> public const double IRREGULAR_RATE = 0.0; - /** - * Constant to indicate that a sample has the next successive time stamp. - * This is an optional optimization to transmit less data per sample. - * The stamp is then deduced from the preceding one according to the stream's sampling rate - * (in the case of an irregular rate, the same time stamp as before will is assumed). - */ + /// <summary> Constant to indicate that a sample has the next successive time stamp. </summary> + /// This is an optional optimization to transmit less data per sample. + /// The stamp is then deduced from the preceding one according to the stream's sampling rate + /// (in the case of an irregular rate, the same time stamp as before will is assumed). public const double DEDUCED_TIMESTAMP = -1.0; - - /** - * A very large time duration (> 1 year) for timeout values. - * Note that significantly larger numbers can cause the timeout to be invalid on some operating systems (e.g., 32-bit UNIX). - */ + /// <summary> A very large time duration (> 1 year) for timeout values. </summary> + /// <remarks>Note that significantly larger numbers can cause the timeout to be invalid on some operating systems (e.g., 32-bit UNIX).</remarks> public const double FOREVER = 32000000.0; - /** - * Data format of a channel (each transmitted sample holds an array of channels). - */ + /// <summary> Data format of a channel (each transmitted sample holds an array of channels). </summary> public enum channel_format_t : byte { - cf_float32 = 1, // For up to 24-bit precision measurements in the appropriate physical unit + /// <summary> For up to 24-bit precision measurements in the appropriate physical unit. </summary> + cf_float32 = 1, - // (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. + /// <summary> For universal numeric data as long as permitted by network & disk budget. + /// (e.g., microvolts). Integers from -16777216 to 16777216 are represented accurately. </summary> + cf_double64 = 2, - // The largest representable integer is 53-bit. - cf_string = 3, // For variable-length ASCII strings or data blobs, such as video frames, + /// <summary> For variable-length ASCII strings or data blobs, such as video frames, + /// the largest representable integer is 53-bit. </summary> + cf_string = 3, - // complex event descriptions, etc. - cf_int32 = 4, // For high-rate digitized formats that require 32-bit precision. Depends critically on + /// <summary> For high-rate digitized formats that require 32-bit precision. Depends critically on complex event descriptions, etc. </summary> + cf_int32 = 4, - // 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 + /// <summary> For very high rate signals (40Khz+) or consumer-grade audio meta-data to represent meaningful units. </summary> + /// Useful for application event codes or other coded data. + cf_int16 = 5, - // (for professional audio float is recommended). - cf_int8 = 6, // For binary signals or other coded data. + /// <summary> For binary signals or other coded data. (for professional audio float is recommended). </summary> + cf_int8 = 6, - // 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. + /// <summary> For now only for future compatibility. Support for this type is not yet exposed in all languages. </summary> + /// Not recommended for encoding string data. + cf_int64 = 7, - // Also, some builds of liblsl will not be able to send or receive data of this type. - cf_undefined = 0 // Can not be transmitted. + /// <summary> Can not be transmitted. Also, some builds of liblsl will not be able to send or receive data of this type. </summary> + cf_undefined = 0 } - /** - * Post-processing options for stream inlets. - */ + /// <summary> Post-processing options for stream inlets. </summary> public enum processing_options_t : byte { - post_none = 0, // No automatic post-processing; return the ground-truth time stamps for manual post-processing + /// <summary> No automatic post-processing; return the ground-truth time stamps for manual post-processing. </summary> + post_none = 0, + + /// <summary> Perform automatic clock synchronization; equivalent to manually adding the TimeCorrection() value (this is the default behavior of the inlet). </summary> + post_clocksync = 1, - // (this is the default behavior of the inlet). - post_clocksync = 1, // Perform automatic clock synchronization; equivalent to manually adding the time_correction() value + /// <summary> Remove jitter from time stamps. This will apply a smoothing algorithm to the received time stamps; to the received time stamps. </summary> + post_dejitter = 2, - // to the received time stamps. - post_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. + /// <summary> Force the time-stamps to be monotonically ascending (only makes sense if timestamps are dejittered). </summary> + post_monotonize = 4, - // the smoothing needs to see a minimum number of samples (30-120 seconds worst-case) until the remaining - // jitter is consistently below 1ms. - post_monotonize = 4, // Force the time-stamps to be monotonically ascending (only makes sense if timestamps are dejittered). - post_threadsafe = 8, // Post-processing is thread-safe (same inlet can be read from by multiple threads); uses somewhat more CPU. - post_ALL = 1 | 2 | 4 | 8 // The combination of all possible post-processing options. + /// <summary> Post-processing is thread-safe (same inlet can be read from by multiple threads); uses somewhat more CPU. </summary> + post_threadsafe = 8, + + /// <summary> The combination of all possible post-processing options. </summary> + post_ALL = 1 | 2 | 4 | 8 } - /** - * Protocol version. - * The major version is protocol_version() / 100; - * The minor version is protocol_version() % 100; - * Clients with different minor versions are protocol-compatible with each other - * while clients with different major versions will refuse to work together. - */ - public static int protocol_version() { return dll.lsl_protocol_version(); } - - /** - * Version of the liblsl library. - * The major version is library_version() / 100; - * The minor version is library_version() % 100; - */ - public static int library_version() { return dll.lsl_library_version(); } - - /** - * Obtain a local system time stamp in seconds. The resolution is better than a millisecond. - * This reading can be used to assign time stamps to samples as they are being acquired. - * If the "age" of a sample is known at a particular time (e.g., from USB transmission - * delays), it can be used as an offset to local_clock() to obtain a better estimate of - * when a sample was actually captured. See stream_outlet::push_sample() for a use case. - */ - public static double local_clock() { return dll.lsl_local_clock(); } + /// <summary> Version of the lsl protocol. </summary> + /// The major version is <c>rotocolVersion()</c> / 100; The minor version is <c>rotocolVersion()</c> % 100; + /// Clients with different minor versions are protocol-compatible with each other while clients with different major versions will refuse to work together. + /// <returns> THe protocole version. </returns> + public static int ProtocolVersion() { return dll.lsl_protocol_version(); } + + /// <summary> Version of the liblsl library. </summary> + /// The major version is LibraryVersion() / 100; The minor version is LibraryVersion() % 100; + /// <returns> THe library version. </returns> + public static int LibraryVersion() { return dll.lsl_library_version(); } + + /// <summary> Obtain a local system time stamp in seconds. </summary> + /// The resolution is better than a millisecond. + /// This reading can be used to assign time stamps to samples as they are being acquired. + /// If the "age" of a sample is known at a particular time (e.g., from USB transmission delays), + /// it can be used as an offset to LocalClock() to obtain a better estimate of when a sample was actually captured. + /// See <c>StreamOutlet::PushSample()</c> for a use case. + /// <returns> The local system time stamp in seconds. </returns> + public static double LocalClock() { return dll.lsl_local_clock(); } // ========================== // === Stream Declaration === // ========================== - /** - * The stream_info object stores the declaration of a data stream. - * Represents the following information: - * a) stream data format (#channels, channel format) - * b) core information (stream name, content type, sampling rate) - * c) optional meta-data about the stream content (channel labels, measurement units, etc.) - * - * Whenever a program wants to provide a new stream on the lab network it will typically first - * create a stream_info to describe its properties and then construct a stream_outlet with it to create - * the stream on the network. Recipients who discover the outlet can query the stream_info; it is also - * written to disk when recording the stream (playing a similar role as a file header). - */ - + /// <summary> The stream_info object stores the declaration of a data stream. </summary> + /// Represents the following information: + /// a) stream data format (#channels, channel format) + /// b) core information (stream name, content type, sampling rate) + /// c) optional meta-data about the stream content (channel labels, measurement units, etc.) + /// + /// Whenever a program wants to provide a new stream on the lab network it will typically first + /// create a stream_info to describe its properties and then construct a stream_outlet with it to create + /// the stream on the network. Recipients who discover the outlet can query the stream_info; it is also + /// 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. - */ + /// <summary> Initializes a new instance of the <see cref="StreamInfo"/> object. </summary> + /// Core stream information is specified here. Any remaining meta-data can be added later. + /// <param name="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> + /// <param name="type"> Content type of the stream. + /// Please see https://github.com/sccn/xdf/wiki/Meta-Data (or web search for: 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> + /// <param name="channelCount"> Number of channels per sample. This stays constant for the lifetime of the stream. </param> + /// <param name="sampling"> The sampling rate (in Hz) as advertised by the data source, if regular (otherwise set to IRREGULAR_RATE). </param> + /// <param name="channelFormat"> 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> + /// <param name="sourceId"> 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.</param> public StreamInfo(string name, string type, int channelCount = 1, double sampling = IRREGULAR_RATE, channel_format_t channelFormat = channel_format_t.cf_float32, string sourceId = "") { @@ -158,7 +147,7 @@ namespace LSL4Unity public StreamInfo(IntPtr handle) { _obj = handle; } - /// Destroy a previously created streaminfo object. + /// <summary> Finalizes an instance of the <see cref="StreamInfo"/> object. </summary> ~StreamInfo() { dll.lsl_destroy_streaminfo(_obj); } // ======================== @@ -166,54 +155,44 @@ namespace LSL4Unity // ======================== // (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). - */ + /// <summary> Name of the stream. </summary> + /// 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). + /// <returns> The name of the stream. </returns> 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). - */ + /// <summary> Content type of the stream. </summary> + /// 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). + /// <returns> The content type of the stream (in <c>string</c>). </returns> 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); } + /// <summary> Number of channels of the stream. A stream has at least one channel; the channel count stays constant for all samples. </summary> + public int ChannelCount() { 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); } + /// <summary> Sampling rate of the stream, according to the source (in Hz). </summary> + /// 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. + /// <returns> The Sampling rate of the stream (in <c>double</c>). </returns> + public double Sampling() { 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); } + /// <summary> Channel format of the stream. </summary> + /// All channels in a stream have the same format. However, a device might offer multiple time-synched streams each with its own format. + /// <returns>The hannel format of the stream (in <see cref="channel_format_t"/> enum) </returns> + public channel_format_t ChannelFormat() { 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)); } + /// <summary> Unique identifier of the stream's source, if available. </summary> + /// 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. + /// <returns> The Identifier (in <c>string</c>). </returns> + public string SourceId() { return Marshal.PtrToStringAnsi(dll.lsl_get_source_id(_obj)); } // ====================================== @@ -221,77 +200,64 @@ namespace LSL4Unity // ====================================== // (these fields are implicitly assigned once bound to an outlet/inlet) - /** - * Protocol version used to deliver the stream. - */ + /// <summary> Protocol version used to deliver the stream. </summary> + /// <returns> The protocol version (in <c>int</c>). </returns> 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). - */ + /// <summary> Creation time stamp of the stream. </summary> + /// This is the time stamp when the stream was first created (as determined via LocalClock() on the providing machine). + /// <returns> The Time Stamp (in <c>double</c>). </returns> + public double CreatedAt() { return dll.lsl_get_created_at(_obj); } + + /// <summary> Unique ID of the stream outlet instance (once assigned). </summary> + /// 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). + /// <returns> The Unique Identifier (in <c>string</c>). </returns> 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)); } + /// <summary> Session ID for the given stream. </summary> + /// 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). + /// <returns> The Session Identifier (in <c>string</c>). </returns> + public string SessionId() { return Marshal.PtrToStringAnsi(dll.lsl_get_session_id(_obj)); } - /** - * Hostname of the providing machine. - */ + /// <summary> Hostname of the providing machine. </summary> + /// <returns> The Hostname (in <c>string</c>). </returns> 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. - */ + /// <summary> Extended description of the stream. </summary> + /// 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). + /// + /// <remarks>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. </remarks> + /// <returns> A <see cref="XMLElement "/> containing the description. </returns> 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 <info>. The info element contains - * one element for each field of the stream_info class, including: - * a) the core elements <name>, <type>, <channel_count>, <nominal_srate>, <channel_format>, <source_id> - * b) the misc elements <version>, <created_at>, <uid>, <session_id>, <v4address>, <v4data_port>, <v4service_port>, <v6address>, <v6data_port>, <v6service_port> - * c) the extended description element <desc> with user-defined sub-elements. - */ - public string as_xml() + /// <summary> Retrieve the entire <see cref="StreamInfo"/> in XML format. </summary> + /// This yields an XML document (in string form) whose top-level element is <info>. The info element contains + /// one element for each field of the stream_info class, including: + /// a) the core elements <c>Name</c>, <c>Type</c>, <c>ChannelCount</c>, <c>Sampling</c>, <c>ChannelFormat</c>, <c>SourceId</c> + /// b) the misc elements <c>Version</c>, <c>CreatedAt</c>, <c>Uid</c>, <c>SessionId</c>, <c>v4address</c>, <c>v4data_port</c>, <c>v4service_port</c>, <c>v6address</c>, <c>v6data_port</c>, <c>v6service_port</c> + /// c) the extended description element <c>desc</c> with user-defined sub-elements. + /// <returns> A <c>string</c> with the entire <see cref="StreamInfo"/>. </returns> + public string AsXML() { IntPtr pXml = dll.lsl_get_xml(_obj); - string strXml = Marshal.PtrToStringAnsi(pXml); + string res = Marshal.PtrToStringAnsi(pXml); dll.lsl_destroy_string(pXml); - return strXml; + return res; } - - /** - * Get access to the underlying handle. - */ + /// <summary> Get access to the underlying handle. </summary> + /// <returns></returns> public IntPtr Handle() { return _obj; } private readonly IntPtr _obj; @@ -302,29 +268,23 @@ namespace LSL4Unity // ==== Stream Outlet ==== // ======================= - /** - * A stream outlet. - * Outlets are used to make streaming data (and the meta-data) available on the lab network. - */ + /// <summary> A stream outlet. </summary> + /// 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. - */ + /// <summary> Initializes a new instance of <see cref="StreamOutlet"/>. This makes the stream discoverable. </summary> + /// <param name="info"> The stream information to use for creating this stream. Stays constant over the lifetime of the outlet. </param> + /// <param name="chunkSize"> Optionally the desired chunk granularity (in samples) for transmission. + /// If unspecified, each push operation yields one chunk. Inlets can override this setting. </param> + /// <param name="maxBuffered">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.</param> public StreamOutlet(StreamInfo info, int chunkSize = 0, int maxBuffered = 360) { _obj = dll.lsl_create_outlet(info.Handle(), chunkSize, maxBuffered); } - /** - * Destructor. - * The stream will no longer be discoverable after destruction and all paired inlets will stop delivering data. - */ + /// <summary> Finalizes an instance of the <see cref="StreamOutlet"/>. </summary> + /// The stream will no longer be discoverable after destruction and all paired inlets will stop delivering data. ~StreamOutlet() { dll.lsl_destroy_outlet(_obj); } @@ -332,34 +292,36 @@ namespace LSL4Unity // === 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 time 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 time = 0.0, bool pushthrough = true) + /// <summary> Push an array of values as a sample into the outlet. </summary> + /// <param name="data"> An array of values to push (one for each channel). </param> + /// <param name="time"> Optionally the capture time of the sample, in agreement with <see cref="LocalClock"/>; if omitted, the current time is used. </param> + /// <param name="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.</param> + public void PushSample(float[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ftp(_obj, data, time, pushthrough ? 1 : 0); } - public void push_sample(double[] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushSample(float[],double,bool)"/> + public void PushSample(double[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_dtp(_obj, data, time, pushthrough ? 1 : 0); } - public void push_sample(int[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_itp(_obj, data, time, pushthrough ? 1 : 0); } + /// <inheritdoc cref="PushSample(float[],double,bool)"/> + public void PushSample(int[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_itp(_obj, data, time, pushthrough ? 1 : 0); } - public void push_sample(short[] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushSample(float[],double,bool)"/> + public void PushSample(short[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_stp(_obj, data, time, pushthrough ? 1 : 0); } - public void push_sample(char[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ctp(_obj, data, time, pushthrough ? 1 : 0); } + /// <inheritdoc cref="PushSample(float[],double,bool)"/> + public void PushSample(char[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_ctp(_obj, data, time, pushthrough ? 1 : 0); } - public void push_sample(string[] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushSample(float[],double,bool)"/> + public void PushSample(string[] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_sample_strtp(_obj, data, time, pushthrough ? 1 : 0); } @@ -369,77 +331,83 @@ namespace LSL4Unity // === Pushing an chunk of samples into the outlet === // =================================================== - /** - * Push a chunk of samples into the outlet. Single time provided. - * @param data A rectangular array of values for multiple samples. - * @param time 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 time = 0.0, bool pushthrough = true) + /// <summary> Push a chunk of samples into the outlet. Single time provided. </summary> + /// <param name="data"> A rectangular array of values for multiple samples. </param> + /// <param name="time"> Optionally the capture time of the sample, in agreement with <see cref="LocalClock"/>; if omitted, the current time is used. </param> + /// <param name="pushthrough"> Optionally whether to push the sample through to the receivers instead of buffering it with subsequent samples. + /// Note that the chunkSize, if specified at outlet construction, takes precedence over the pushthrough flag.</param> + public void PushChunk(float[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ftp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - public void push_chunk(double[,] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double,bool)"/> + public void PushChunk(double[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_dtp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - public void push_chunk(int[,] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double,bool)"/> + public void PushChunk(int[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_itp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - public void push_chunk(short[,] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double,bool)"/> + public void PushChunk(short[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_stp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - public void push_chunk(char[,] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double,bool)"/> + public void PushChunk(char[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_ctp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - public void push_chunk(string[,] data, double time = 0.0, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double,bool)"/> + public void PushChunk(string[,] data, double time = 0.0, bool pushthrough = true) { dll.lsl_push_chunk_strtp(_obj, data, (uint) data.Length, time, pushthrough ? 1 : 0); } - /** - * Push a chunk of multiplexed samples into the outlet. One time per sample is provided. - * @param data A rectangular array of values for multiple samples. - * @param times An array of time 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[] times, bool pushthrough = true) + + /// <summary> Push a chunk of multiplexed samples into the outlet. One time per sample is provided. </summary> + /// <param name="data"> A rectangular array of values for multiple samples. </param> + /// <param name="times"> An array of time values holding time stamps for each sample in the data buffer. </param> + /// <param name="pushthrough"> Optionally whether to push the sample through to the receivers instead of buffering it with subsequent samples. + /// Note that the chunkSize, if specified at outlet construction, takes precedence over the pushthrough flag.</param> + public void PushChunk(float[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_ftnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } - public void push_chunk(double[,] data, double[] times, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double[],bool)"/> + public void PushChunk(double[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_dtnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } - public void push_chunk(int[,] data, double[] times, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double[],bool)"/> + public void PushChunk(int[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_itnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } - public void push_chunk(short[,] data, double[] times, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double[],bool)"/> + public void PushChunk(short[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_stnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } - public void push_chunk(char[,] data, double[] times, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double[],bool)"/> + public void PushChunk(char[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_ctnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } - public void push_chunk(string[,] data, double[] times, bool pushthrough = true) + /// <inheritdoc cref="PushChunk(float[,],double[],bool)"/> + public void PushChunk(string[,] data, double[] times, bool pushthrough = true) { dll.lsl_push_chunk_strtnp(_obj, data, (uint) data.Length, times, pushthrough ? 1 : 0); } @@ -449,22 +417,19 @@ namespace LSL4Unity // === 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; } + /// <summary> Check whether consumers are currently registered. </summary> + /// While it does not hurt, there is technically no reason to push samples if there is no consumer. + /// <returns> <c>true</c> or <c>false</c>. </returns> + public bool HaveConsumers() { 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) { return dll.lsl_wait_for_consumers(_obj) > 0; } + /// <summary> Wait until some consumer shows up (without wasting resources). </summary> + /// <param name="timeout"> The timeout.</param> + /// <returns> True if the wait was successful, false if the timeout expired. </returns> + public bool WaitForConsumers(double timeout) { 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). - */ + /// <summary> Retrieve the stream info provided by this outlet. </summary> + /// This is what was used to create the stream (and also has the Additional Network Information fields assigned). + /// <returns> A <see cref="StreamInfo"/> </returns> public StreamInfo Info() { return new StreamInfo(dll.lsl_get_info(_obj)); } private readonly IntPtr _obj; @@ -475,22 +440,17 @@ namespace LSL4Unity // ==== Resolve Functions ==== // =========================== - /** - * Resolve all streams on the network. - * This function returns all currently available streams from any outlet on the network. - * The network is usually the subnet specified at the local router, but may also include - * a multicast group of machines (given that the network supports it), or list of hostnames. - * These details may optionally be customized by the experimenter in a configuration file - * (see Network Connectivity in the LSL wiki). - * This is the default mechanism used by the browsing programs and the recording program. - * @param wait_time The waiting time for the operation, in seconds, to search for streams. - * Warning: If this is too short (less than 0.5s) only a subset (or none) of the - * outlets that are present on the network may be returned. - * @return An array of stream info objects (excluding their desc field), any of which can - * subsequently be used to open an inlet. The full info can be retrieve from the inlet. - */ - - public static StreamInfo[] resolve_streams(double waitTime = 1.0) + /// <summary> Resolve all streams on the network. </summary> + /// This function returns all currently available streams from any outlet on the network. + /// The network is usually the subnet specified at the local router, + /// but may also include a multicast group of machines (given that the network supports it), or list of hostnames. + /// These details may optionally be customized by the experimenter in a configuration file (see Network Connectivity in the LSL wiki). + /// This is the default mechanism used by the browsing programs and the recording program. + /// <param name="waitTime"> The waiting time for the operation, in seconds, to search for streams. </param> + /// <returns> An array of stream info objects (excluding their desc field), any of which can subsequently be used to open an inlet. + /// The full info can be retrieve from the inlet. </returns> + /// <remarks> If [waitTime] is too short (less than 0.5s) only a subset (or none) of the outlets that are present on the network may be returned.</remarks> + public static StreamInfo[] ResolveStreams(double waitTime = 1.0) { IntPtr[] buf = new IntPtr[1024]; int num = dll.lsl_resolve_all(buf, (uint) buf.Length, waitTime); @@ -499,18 +459,15 @@ namespace LSL4Unity return res; } - /** - * Resolve all streams with a specific value for a given property. - * If the goal is to resolve a specific stream, this method is preferred over resolving all streams and then selecting the desired one. - * @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 minimum Optionally return at least this number of streams. - * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout). - * If the timeout expires, less than the desired number of streams (possibly none) will be returned. - * @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) + /// <summary> Resolve all streams with a specific value for a given property. </summary> + /// If the goal is to resolve a specific stream, this method is preferred over resolving all streams and then selecting the desired one. + /// <param name="prop"> The <see cref="StreamInfo"/> property that should have a specific value (e.g., "name", "type", "SourceId", or "desc/manufaturer"). </param> + /// <param name="value"> The string value that the property should have (e.g., "EEG" as the type property). </param> + /// <param name="minimum"> Optionally return at least this number of streams. </param> + /// <param name="timeout"> Optionally a timeout of the operation, in seconds (default: no timeout). + /// If the timeout expires, less than the desired number of streams (possibly none) will be returned. </param> + /// <returns> An array of matching stream info objects (excluding their meta-data), any of which can subsequently be used to open an inlet. </returns> + public static StreamInfo[] ResolveStream(string prop, string value, int minimum = 1, double timeout = FOREVER) { IntPtr[] buf = new IntPtr[1024]; int num = dll.lsl_resolve_byprop(buf, (uint) buf.Length, prop, value, minimum, timeout); @@ -519,18 +476,16 @@ namespace LSL4Unity return res; } - /** - * Resolve all streams that match a given predicate. - * Advanced query that allows to impose more conditions on the retrieved streams; the given string is an XPath 1.0 - * predicate for the <info> node (omitting the surrounding []'s), see also http://en.wikipedia.org/w/index.php?title=XPath_1.0&oldid=474981951. - * @param pred The predicate string, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32" - * @param minimum Return at least this number of streams. - * @param timeout Optionally a timeout of the operation, in seconds (default: no timeout). - * If the timeout expires, less than the desired number of streams (possibly none) will be returned. - * @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) + /// <summary> Resolve all streams that match a given predicate. </summary> + /// Advanced query that allows to impose more conditions on the retrieved streams; + /// the given string is an XPath 1.0 predicate for the info node (omitting the surrounding []'s), + /// <param name="pred"> The predicate string, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32". </param> + /// <param name="minimum"> Optionally return at least this number of streams. </param> + /// <param name="timeout"> Optionally a timeout of the operation, in seconds (default: no timeout). + /// If the timeout expires, less than the desired number of streams (possibly none) will be returned. </param> + /// <returns> An array of matching stream info objects (excluding their meta-data), any of which can subsequently be used to open an inlet. </returns> + /// <seealso cref="http://en.wikipedia.org/w/index.php?title=XPath_1.0&oldid=474981951"/> + public static StreamInfo[] ResolveStream(string pred, int minimum = 1, double timeout = FOREVER) { IntPtr[] buf = new IntPtr[1024]; int num = dll.lsl_resolve_bypred(buf, (uint) buf.Length, pred, minimum, timeout); @@ -544,110 +499,95 @@ namespace LSL4Unity // ==== Stream Inlet ==== // ====================== - /** - * A stream inlet. - * Inlets are used to receive streaming data (and meta-data) from the lab network. - */ + /// <summary> A stream inlet. </summary> + /// 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). - */ + /// <summary> Initializes a new instance of <see cref="StreamInlet"/> from a resolved stream info. </summary> + /// <param name="info"> A resolved stream info object (as coming from one of the resolver functions). </param> + /// <param name="maxBuflen"> 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> + /// <param name="maxChunklen"> 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> + /// <param name="recover"> Try to silently recover lost streams that are recoverable (=those that that have a SourceId set). + /// In all other cases (recover is false or the stream is not recoverable) functions may throw a <see cref="LostException"/> + /// if the stream's source is lost (e.g., due to an app or computer crash). </param> + /// <remarks> The <see cref="StreamInlet"/> may also be constructed with a fully-specified <see cref="StreamInfo"/> + /// 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). </remarks> public StreamInlet(StreamInfo info, int maxBuflen = 360, int maxChunklen = 0, bool recover = true) { _obj = dll.lsl_create_inlet(info.Handle(), maxBuflen, maxChunklen, recover ? 1 : 0); } - /** - * Destructor. - * The inlet will automatically disconnect if destroyed. - */ + /// <summary> Finalizes an instance of <see cref="StreamInlet"/>. </summary> + /// The inlet will automatically disconnect if destroyed. ~StreamInlet() { dll.lsl_destroy_inlet(_obj); } - /** - * 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). - */ - + /// <summary> Retrieve the complete information of the given stream, including the extended description. </summary> + /// Can be invoked at any time of the stream's lifetime. + /// <param name="timeout"> Optional timeout of the operation (default: no timeout). </param> + /// <returns> <see cref="StreamInfo"/>. </returns> + /// <exception cref="TimeoutException"> If the timeout expires. </exception> + /// <exception cref="LostException"> If the stream source has been lost. </exception> public StreamInfo Info(double timeout = FOREVER) { int ec = 0; IntPtr res = dll.lsl_get_fullinfo(_obj, timeout, ref ec); - check_error(ec); + CheckError(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) + /// <summary> Subscribe to the data stream. </summary> + /// All samples pushed in at the other end from this moment onwards will be queued and + /// eventually be delivered in response to <see cref="PullSample(float[],double)"/> or <see cref="PullChunk(float[,],double[],double)"/> calls. + /// Pulling a sample without some preceding OpenStream is permitted (the stream will then be opened implicitly). + /// <param name="timeout"> Optional timeout of the operation (default: no timeout).</param> + /// <exception cref="TimeoutException"> If the timeout expires. </exception> + /// <exception cref="LostException"> If the stream source has been lost. </exception> + public void OpenStream(double timeout = FOREVER) { int ec = 0; dll.lsl_open_stream(_obj, timeout, ref ec); - check_error(ec); + CheckError(ec); } - /** - * Set post-processing flags to use. By default, the inlet performs NO post-processing and returns the - * ground-truth time stamps, which can then be manually synchronized using time_correction(), and then - * smoothed/dejittered if desired. This function allows automating these two and possibly more operations. - * Warning: when you enable this, you will no longer receive or be able to recover the original time stamps. - * @param flags An integer that is the result of bitwise OR'ing one or more options from processing_options_t - * together (e.g., post_clocksync|post_dejitter); the default is to enable all options. - */ - public void set_postprocessing(processing_options_t postFlags = processing_options_t.post_ALL) { dll.lsl_set_postprocessing(_obj, postFlags); } - - /** - * 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) + /// <summary> Set post-processing flags to use. </summary> + /// By default, the inlet performs NO post-processing and returns the ground-truth time stamps, + /// which can then be manually synchronized using TimeCorrection(), and then smoothed/dejittered if desired. + /// This function allows automating these two and possibly more operations. + /// <param name="flags"> An integer that is the result of bitwise OR'ing one or more options + /// from <see cref="processing_options_t"/> together (e.g., post_clocksync|post_dejitter); the default is to enable all options. </param> + /// <remarks> When you enable this, you will no longer receive or be able to recover the original time stamps. </remarks> + public void SetPostprocessing(processing_options_t flags = processing_options_t.post_ALL) { dll.lsl_set_postprocessing(_obj, flags); } + + /// <summary> Drop the current data stream. </summary> + /// 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 CloseStream() to not waste unnecessary system and network resources. + public void CloseStream() { dll.lsl_close_stream(_obj); } + + /// <summary> Retrieve an estimated time correction offset for the given stream. </summary> + /// 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). + /// <param name="timeout"> Optional timeout to acquire the first time-correction estimate (default: no timeout). </param> + /// <returns> The time correction estimate. This is the number that needs to be added to a time stamp + /// that was remotely generated via <c>lsl_local_clock()</c> to map it into the local clock domain of this machine. </returns> + /// <exception cref="TimeoutException"> If the timeout expires. </exception> + /// <exception cref="LostException"> If the stream source has been lost. </exception> + public double TimeCorrection(double timeout = FOREVER) { int ec = 0; double res = dll.lsl_time_correction(_obj, timeout, ref ec); - check_error(ec); + CheckError(ec); return res; } @@ -655,62 +595,63 @@ namespace LSL4Unity // === 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) + /// <summary> Pull a sample from the inlet and read it into an array of values. Handles type checking & conversion. </summary> + /// <param name="sample"> An array to hold the resulting values. </param> + /// <param name="timeout"> Optional, the timeout for this operation, if any. Use 0.0 to make the function non-blocking. </param> + /// <returns>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 <see cref="TimeCorrection"/> to it. </returns> + /// <exception cref="LostException"> If the stream source has been lost. </exception> + public double PullSample(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); + CheckError(ec); return res; } - public double pull_sample(double[] sample, double timeout = FOREVER) + /// <inheritdoc cref="PullSample(float[],double)"/> + public double PullSample(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); + CheckError(ec); return res; } - public double pull_sample(int[] sample, double timeout = FOREVER) + /// <inheritdoc cref="PullSample(float[],double)"/> + public double PullSample(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); + CheckError(ec); return res; } - public double pull_sample(short[] sample, double timeout = FOREVER) + /// <inheritdoc cref="PullSample(float[],double)"/> + public double PullSample(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); + CheckError(ec); return res; } - public double pull_sample(char[] sample, double timeout = FOREVER) + /// <inheritdoc cref="PullSample(float[],double)"/> + public double PullSample(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); + CheckError(ec); return res; } - public double pull_sample(string[] sample, double timeout = FOREVER) + /// <inheritdoc cref="PullSample(float[],double)"/> + public double PullSample(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); + CheckError(ec); try { for (int k = 0; k < tmp.Length; k++) { sample[k] = Marshal.PtrToStringAnsi(tmp[k]); } @@ -727,63 +668,65 @@ namespace LSL4Unity // === 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[,] buffer, double[] times, double timeout = 0.0) + /// <summary> Pull a chunk of data from the inlet. </summary> + /// <param name="buffer"> A pre-allocated buffer where the channel data shall be stored. </param> + /// <param name="times"> A pre-allocated buffer where time stamps shall be stored. </param> + /// <param name="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.</param> + /// <returns> Number of samples written to the data and timestamp buffers.</returns> + /// <exception cref="LostException"> If the stream source has been lost. </exception> + public int PullChunk(float[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_f(_obj, buffer, times, (uint) buffer.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); return (int) res / buffer.GetLength(1); } - public int pull_chunk(double[,] buffer, double[] times, double timeout = 0.0) + /// <inheritdoc cref="PullChunk(float[,],double[],double)"/> + public int PullChunk(double[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_d(_obj, buffer, times, (uint) buffer.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); return (int) res / buffer.GetLength(1); } - public int pull_chunk(int[,] buffer, double[] times, double timeout = 0.0) + /// <inheritdoc cref="PullChunk(float[,],double[],double)"/> + public int PullChunk(int[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_i(_obj, buffer, times, (uint) buffer.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); return (int) res / buffer.GetLength(1); } - public int pull_chunk(short[,] buffer, double[] times, double timeout = 0.0) + /// <inheritdoc cref="PullChunk(float[,],double[],double)"/> + public int PullChunk(short[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_s(_obj, buffer, times, (uint) buffer.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); return (int) res / buffer.GetLength(1); } - public int pull_chunk(char[,] buffer, double[] times, double timeout = 0.0) + /// <inheritdoc cref="PullChunk(float[,],double[],double)"/> + public int PullChunk(char[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; uint res = dll.lsl_pull_chunk_c(_obj, buffer, times, (uint) buffer.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); return (int) res / buffer.GetLength(1); } - public int pull_chunk(string[,] buffer, double[] times, double timeout = 0.0) + /// <inheritdoc cref="PullChunk(float[,],double[],double)"/> + public int PullChunk(string[,] buffer, double[] times, double timeout = 0.0) { int ec = 0; IntPtr[,] tmp = new IntPtr[buffer.GetLength(0), buffer.GetLength(1)]; uint res = dll.lsl_pull_chunk_str(_obj, tmp, times, (uint) tmp.Length, (uint) times.Length, timeout, ref ec); - check_error(ec); + CheckError(ec); try { for (int s = 0; s < tmp.GetLength(0); s++) @@ -801,22 +744,21 @@ namespace LSL4Unity return (int) res / buffer.GetLength(1); } - /** - * 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); } + /// <summary> Query whether samples are currently available for immediate pickup. </summary> + /// <returns> Number of samples available. </returns> + /// <remarks> that it is not a good idea to use <see cref="SamplesAvailable"/> to determine whether a <c>pull_*()</c> 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). </remarks> + public int SamplesAvailable() { 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; } + /// <summary> Query whether the clock was potentially reset since the last call to <see cref="WasClockReset"/>. </summary> + /// This is a rarely-used function that is only useful to applications that combine multiple <see cref="TimeCorrection"/> values to estimate precise clock drift; + /// it allows to tolerate cases where the source machine was hot-swapped or restarted in between two measurements. + /// <returns> <c>true</c> if clock waas reset... </returns> + public bool WasClockReset() { return (int) dll.lsl_was_clock_reset(_obj) != 0; } private readonly IntPtr _obj; } @@ -826,113 +768,103 @@ namespace LSL4Unity // ==== 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. - */ + /// <summary> A lightweight XML element tree; models the <see cref="StreamInfo.Desc"/> field of <see cref="StreamInfo"/>. </summary> + /// 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. + /// <seealso cref="http://pugixml.googlecode.com/svn/tags/latest/docs/manual/access.html"/> public struct XMLElement { + /// <summary> Initializes a new instance of <see cref="XMLElement"/> struct. </summary> + /// <param name="handle"> The handle. </param> 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)); } + /// <summary> Get the first child of the element. </summary> + public XMLElement FirstChild() { 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)); } + /// <summary> Get the last child of the element. </summary> + public XMLElement LastChild() { 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)); } + /// <summary> Get the next sibling in the children list of the parent node. </summary> + public XMLElement NextSibling() { 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)); } + /// <summary> Get the previous sibling in the children list of the parent node. </summary> + public XMLElement PreviousSibling() { return new XMLElement(dll.lsl_previous_sibling(_obj)); } - /// Get the parent node. + /// <summary> Get the parent node. </summary> public XMLElement Parent() { return new XMLElement(dll.lsl_parent(_obj)); } // === Tree Navigation by Name === - /// Get a child with a specified name. + /// <summary> Get a child with a specified name. </summary> 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)); } + /// <summary> Get the next sibling with the specified name. </summary> + public XMLElement NextSibling(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)); } + /// <summary> Get the previous sibling with the specified name. </summary> + public XMLElement PreviousSibling(string name) { return new XMLElement(dll.lsl_previous_sibling_n(_obj, name)); } // === Content Queries === - /// Whether this node is empty. + /// <summary> Whether this node is empty. </summary> 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; } + /// <summary> Whether this is a text body (instead of an XML element). True both for plain char data and CData. </summary> + public bool IsText() { return dll.lsl_is_text(_obj) != 0; } - /// Name of the element. + /// <summary> Name of the element. </summary> public string Name() { return Marshal.PtrToStringAnsi(dll.lsl_name(_obj)); } - /// Value of the element. + /// <summary> Value of the element. </summary> 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)); } + /// <summary> Get child value (value of the first child that is text). </summary> + public string ChildValue() { 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)); } + /// <summary> Get child value of a child with a specified name. </summary> + public string ChildValue(string name) { return Marshal.PtrToStringAnsi(dll.lsl_child_value_n(_obj, name)); } // === Modification === - /** - * 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)); } + /// <summary> Append a child node with a given name, which has a (nameless) plain-text child with the given text value. </summary> + public XMLElement AppendChildValue(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)); } + /// <summary> Prepend a child node with a given name, which has a (nameless) plain-text child with the given text value. </summary> + public XMLElement PrependChildValue(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; } + /// <summary> Set the text value of the (nameless) plain-text child of a named child node. </summary> + public bool SetChildValue(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; } + /// <summary> Set the element's name. </summary> + /// <returns> <c>false</c> if the node is empty. </returns> + public bool SetName(string name) { return dll.lsl_set_name(_obj, name) != 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; } + /// <summary> Set the element's value. </summary> + /// <returns> <c>false</c> if the node is empty. </returns> + public bool SetValue(string value) { return dll.lsl_set_value(_obj, value) != 0; } - /// Append a child element with the specified name. - public XMLElement append_child(string name) { return new XMLElement(dll.lsl_append_child(_obj, name)); } + /// <summary> Append a child element with the specified name. </summary> + public XMLElement AppendChild(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)); } + /// <summary> Prepend a child element with the specified name. </summary> + public XMLElement PrependChild(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)); } + /// <summary> Append a copy of the specified element as a child. </summary> + public XMLElement AppendCopy(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)); } + /// <summary> Prepend a child element with the specified name. </summary> + public XMLElement PrependCopy(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); } + /// <summary> Remove a child element with the specified name. </summary> + public void RemoveChild(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); } + /// <summary> Remove a specified child element. </summary> + public void RemoveChild(XMLElement e) { dll.lsl_remove_child(_obj, e._obj); } private readonly IntPtr _obj; } @@ -942,54 +874,39 @@ namespace LSL4Unity // === 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. - */ - + /// <summary> 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. </summary> public class ContinuousResolver { - /** - * 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. - */ + /// <summary> Initializes a new instance of the <see cref="ContinuousResolver"/> class that resolves all streams on the network. </summary> + /// This is analogous to the functionality offered by the free function <see cref="ResolveStreams"/>. + /// <param name="forgetAfter"> 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.</param> public ContinuousResolver(double forgetAfter = 5.0) { _obj = dll.lsl_create_continuous_resolver(forgetAfter); } - /** - * 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. - */ + /// <summary> Initializes a new instance of the <see cref="ContinuousResolver"/> class that resolves all streams with a specific value for a given property. </summary> + /// This is analogous to the functionality provided by the free function <see cref="liblsl.ResolveStream(string,string,int,double)"/>. + /// <param name="prop"> The <see cref="StreamInfo"/> property that should have a specific value (e.g., "name", "type", "SourceId", or "desc/manufaturer"). </param> + /// <param name="value"> The string value that the property should have (e.g., "EEG" as the type property). </param> + /// <param name="forgetAfter"> 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.</param> public ContinuousResolver(string prop, string value, double forgetAfter = 5.0) { _obj = dll.lsl_create_continuous_resolver_byprop(prop, value, forgetAfter); } - /** - * 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. - */ + /// <summary> Initializes a new instance of the <see cref="ContinuousResolver"/> class that resolves all streams that match a given XPath 1.0 predicate. </summary> + /// <param name="pred"> The predicate string, e.g. "name='BioSemi'" or "type='EEG' and starts-with(name,'BioSemi') and count(info/desc/channel)=32" </param> + /// This is analogous to the functionality provided by the free function <see cref="liblsl.ResolveStream(string,int,double)"/>. + /// <param name="forgetAfter"> 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.</param> public ContinuousResolver(string pred, double forgetAfter = 5.0) { _obj = dll.lsl_create_continuous_resolver_bypred(pred, forgetAfter); } - /** - * Destructor. - */ + /// <summary> Finalizes an instance of the <see cref="ContinuousResolver"/> class. </summary> ~ContinuousResolver() { dll.lsl_destroy_continuous_resolver(_obj); } - /** - * 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. - */ + /// <summary> Obtain the set of currently present streams on the network (i.e. resolve result). </summary> + /// <returns> An array of matching stream info objects (excluding their meta-data), any of which can subsequently be used to open an inlet. </returns> public StreamInfo[] Results() { IntPtr[] buf = new IntPtr[1024]; @@ -1006,9 +923,8 @@ namespace LSL4Unity // === Exception Types === // ======================= - /** - * Exception class that indicates that a stream inlet's source has been irrecoverably lost. - */ + /// <summary> Exception class that indicates that a stream inlet's source has been irrecoverably lost. </summary> + /// <seealso cref="System.Exception" /> public class LostException : Exception { public LostException() { } @@ -1017,9 +933,8 @@ namespace LSL4Unity protected LostException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } - /** - * Exception class that indicates that an internal error has occurred inside liblsl. - */ + /// <summary> Exception class that indicates that an internal error has occurred inside liblsl. </summary> + /// <seealso cref="System.Exception" /> public class InternalException : Exception { public InternalException() { } @@ -1028,14 +943,18 @@ namespace LSL4Unity protected InternalException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } } - /** - * Check an error condition and throw an exception if appropriate. - */ - public static void check_error(int ec) + /// <summary> Check an error condition and throw an exception if appropriate. </summary> + /// <param name="code"> The error code. </param> + /// <exception cref="TimeoutException"> The operation failed due to a timeout. </exception> + /// <exception cref="LostException"> The stream has been lost. </exception> + /// <exception cref="ArgumentException"> An argument was incorrectly specified (e.g., wrong format or wrong length). </exception> + /// <exception cref="InternalException"> An internal internal error has occurred. </exception> + /// <exception cref="Exception"> An unknown error has occurred. </exception> + public static void CheckError(int code) { - if (ec < 0) + if (code < 0) { - switch (ec) + switch (code) { case -1: throw new TimeoutException("The operation failed due to a timeout."); case -2: throw new LostException("The stream has been lost."); diff --git a/Scripts/AInlet.cs b/Scripts/AInlet.cs index 1b55dadbb0547e4359937bee30ebae9025bfea0a..d0e827862290c8a26a67ed82f18cadb0571316ad 100644 --- a/Scripts/AInlet.cs +++ b/Scripts/AInlet.cs @@ -7,6 +7,8 @@ using UnityEngine; namespace LSL4Unity.Scripts { + /// <summary> Float Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class AFloatInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -26,17 +28,17 @@ namespace LSL4Unity.Scripts private void Start() { - var expectedStreamHasAName = !StreamName.Equals(""); - var expectedStreamHasAType = !StreamType.Equals(""); + var hasAName = StreamName.Length != 0; + var hasAType = StreamType.Length != 0; - if (!expectedStreamHasAName && !expectedStreamHasAType) + if (!hasAName && !hasAType) { Debug.LogError("Inlet has to specify a name or a type before it is able to lookup a stream."); enabled = false; return; } - if (expectedStreamHasAName) + if (hasAName) { Debug.Log("Creating LSL resolver for stream " + StreamName); _resolver = new liblsl.ContinuousResolver("name", StreamName); @@ -53,10 +55,7 @@ namespace LSL4Unity.Scripts } /// <summary> Override this method in the subclass to specify what should happen during Start(). </summary> - protected virtual void AdditionalStart() - { - //By default, do nothing. - } + protected void AdditionalStart() { } //By default, do nothing. private IEnumerator ResolveExpectedStream() { @@ -68,7 +67,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -79,14 +78,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -98,8 +97,8 @@ namespace LSL4Unity.Scripts } /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <param name="sample"> The Incomming Sample. </param> + /// <param name="time"> The current Time. </param> protected abstract void Process(float[] sample, double time); private void FixedUpdate() @@ -113,6 +112,8 @@ namespace LSL4Unity.Scripts } } + /// <summary> Double Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class ADoubleInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -171,7 +172,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(GetStreamInfoFrom(results)); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); } yield return null; @@ -189,14 +190,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -207,9 +208,7 @@ namespace LSL4Unity.Scripts } } - /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <inheritdoc cref="AFloatInlet.Process"/> protected abstract void Process(double[] sample, double time); private void FixedUpdate() @@ -223,6 +222,8 @@ namespace LSL4Unity.Scripts } } + /// <summary> Char Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class ACharInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -280,7 +281,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -291,14 +292,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -309,9 +310,7 @@ namespace LSL4Unity.Scripts } } - /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <inheritdoc cref="AFloatInlet.Process"/> protected abstract void Process(char[] sample, double time); private void FixedUpdate() @@ -325,6 +324,8 @@ namespace LSL4Unity.Scripts } } + /// <summary> Float Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class AShortInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -381,7 +382,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -392,14 +393,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -410,9 +411,7 @@ namespace LSL4Unity.Scripts } } - /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <inheritdoc cref="AFloatInlet.Process"/> protected abstract void Process(short[] sample, double time); private void FixedUpdate() @@ -426,6 +425,8 @@ namespace LSL4Unity.Scripts } } + /// <summary> Int Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class AIntInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -482,7 +483,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -493,14 +494,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -511,9 +512,7 @@ namespace LSL4Unity.Scripts } } - /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <inheritdoc cref="AFloatInlet.Process"/> protected abstract void Process(int[] sample, double time); private void FixedUpdate() @@ -527,6 +526,8 @@ namespace LSL4Unity.Scripts } } + /// <summary> String Inlet. </summary> + /// <seealso cref="UnityEngine.MonoBehaviour" /> public abstract class AStringInlet : MonoBehaviour { public enum UpdateMoment { FixedUpdate, Update } @@ -583,7 +584,7 @@ namespace LSL4Unity.Scripts _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -594,14 +595,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -612,9 +613,7 @@ namespace LSL4Unity.Scripts } } - /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <inheritdoc cref="AFloatInlet.Process"/> protected abstract void Process(string[] sample, double time); private void FixedUpdate() diff --git a/Scripts/BaseInlet.cs b/Scripts/BaseInlet.cs index cef36260cdf4f5fc58f8f0dc9a45019299269b0e..79d87566f6acd8af1dd774c04143879541c0375a 100644 --- a/Scripts/BaseInlet.cs +++ b/Scripts/BaseInlet.cs @@ -34,7 +34,7 @@ namespace LSL4Unity.Scripts } /// <summary> Callback method for the Resolver gets called each time the resolver found a stream. </summary> - /// <param name="stream"></param> + /// <param name="stream"> The stream. </param> public virtual void AStreamIsFound(LSLStreamInfoWrapper stream) { if (!IsTheExpected(stream)) { return; } @@ -47,10 +47,8 @@ namespace LSL4Unity.Scripts OnStreamAvailable(); } - /// <summary> - /// Callback method for the Resolver gets called each time the resolver misses a stream within its cache - /// </summary> - /// <param name="stream"></param> + /// <summary> Callback method for the Resolver gets called each time the resolver misses a stream within its cache. </summary> + /// <param name="stream"> The stream. </param> public virtual void AStreamGotLost(LSLStreamInfoWrapper stream) { if (!IsTheExpected(stream)) { return; } @@ -60,6 +58,9 @@ namespace LSL4Unity.Scripts OnStreamLost(); } + /// <summary> Determines if the specified stream is the expected stream. </summary> + /// <param name="stream"> The stream. </param> + /// <returns> <c>true</c> if if the specified stream is the expected stream; otherwise, <c>false</c>. </returns> protected virtual bool IsTheExpected(LSLStreamInfoWrapper stream) { bool predicate = StreamName.Equals(stream.Name); @@ -68,14 +69,19 @@ namespace LSL4Unity.Scripts return predicate; } + /// <summary> Pull the samples. </summary> protected abstract void PullSamples(); + /// <summary> Called when a stream is available. </summary> + /// <exception cref="NotImplementedException">Please override this method in a derived class!</exception> protected virtual void OnStreamAvailable() { // base implementation may not decide what happens when the stream gets available throw new NotImplementedException("Please override this method in a derived class!"); } + /// <summary> Called when a stream is lost. </summary> + /// <exception cref="NotImplementedException">Please override this method in a derived class!</exception> protected virtual void OnStreamLost() { // base implementation may not decide what happens when the stream gets lost @@ -83,8 +89,12 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletFloatSamples : ABaseInlet { + /// <summary> Override this method in the subclass to specify what should happen when samples are available. </summary> + /// <param name="sample"> The Incomming Sample. </param> + /// <param name="time"> The current Time. </param> protected abstract void Process(float[] sample, double time); protected float[] Sample; @@ -95,14 +105,14 @@ namespace LSL4Unity.Scripts try { - double time = Inlet.pull_sample(Sample, 0.0f); + double time = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(time) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, time); // pull as long samples are available - while (Math.Abs(time = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, time); } + while (Math.Abs(time = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, time); } } } catch (ArgumentException aex) @@ -114,8 +124,10 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletDoubleSamples : ABaseInlet { + /// <inheritdoc cref="InletFloatSamples.Process"/> protected abstract void Process(double[] sample, double time); protected double[] Sample; @@ -126,14 +138,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = Inlet.pull_sample(Sample, 0.0f); + double lastTimeStamp = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -145,8 +157,10 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletIntSamples : ABaseInlet { + /// <inheritdoc cref="InletFloatSamples.Process"/> protected abstract void Process(int[] sample, double time); protected int[] Sample; @@ -157,14 +171,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = Inlet.pull_sample(Sample, 0.0f); + double lastTimeStamp = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -176,8 +190,10 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletCharSamples : ABaseInlet { + /// <inheritdoc cref="InletFloatSamples.Process"/> protected abstract void Process(char[] sample, double time); protected char[] Sample; @@ -188,14 +204,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = Inlet.pull_sample(Sample, 0.0f); + double lastTimeStamp = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -207,8 +223,10 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletStringSamples : ABaseInlet { + /// <inheritdoc cref="InletFloatSamples.Process"/> protected abstract void Process(string[] sample, double time); protected string[] Sample; @@ -219,14 +237,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = Inlet.pull_sample(Sample, 0.0f); + double lastTimeStamp = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -238,8 +256,10 @@ namespace LSL4Unity.Scripts } } + /// <inheritdoc/> public abstract class InletShortSamples : ABaseInlet { + /// <inheritdoc cref="InletFloatSamples.Process"/> protected abstract void Process(short[] sample, double time); protected short[] Sample; @@ -250,14 +270,14 @@ namespace LSL4Unity.Scripts try { - double lastTimeStamp = Inlet.pull_sample(Sample, 0.0f); + double lastTimeStamp = Inlet.PullSample(Sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(Sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = Inlet.pull_sample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = Inlet.PullSample(Sample, 0.0f)) > Constants.TOLERANCE) { Process(Sample, lastTimeStamp); } } } catch (ArgumentException aex) diff --git a/Scripts/Examples/DemoInletForFloatSamples.cs b/Scripts/Examples/DemoInletForFloatSamples.cs index e1e9c2a5616af6019bd2ec8a8897e185a5d99fb7..68d58a9dc80faa8ece86b223d126fd807992698b 100644 --- a/Scripts/Examples/DemoInletForFloatSamples.cs +++ b/Scripts/Examples/DemoInletForFloatSamples.cs @@ -43,8 +43,8 @@ namespace LSL4Unity.Scripts.Examples /// coroutines for more complexe processing tasks to distribute processing time over /// several frames /// </summary> - /// <param name="sample"></param> - /// <param name="time"></param> + /// <param name="sample"> The Incomming Sample. </param> + /// <param name="time"> The current Time. </param> protected override void Process(float[] sample, double time) { //Assuming that a sample contains at least 3 values for x,y,z diff --git a/Scripts/LSLCommon.cs b/Scripts/LSLCommon.cs index 0b4efda521bba3ea1359fea26f0b390f4f470fc8..33e77cf8938c0b9ee8b548bd2b6023af9e093254 100644 --- a/Scripts/LSLCommon.cs +++ b/Scripts/LSLCommon.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; namespace LSL4Unity.Scripts @@ -7,12 +7,10 @@ namespace LSL4Unity.Scripts { private const int DEFAULT_PLATTFORM_SPECIFIC_FRAMERATE = -1; - /// <summary> - /// - EXPERIMENTAL - - /// Use this to get the sampling rate on which most post processing procedures rely - like importing recorded date as .xdf file to EEGLAB. - /// </summary> - /// <param name="moment">Enumeration value for FixedUpdate, Update, LateUpdate ...</param> - /// <param name="setRefreshRateToDisplay">Set this to false, if another framerate has been specified manually</param> + /// <summary> - EXPERIMENTAL - + /// Use this to get the sampling rate on which most post processing procedures rely - like importing recorded date as .xdf file to EEGLAB. </summary> + /// <param name="moment"> Enumeration value for FixedUpdate, Update, LateUpdate ... </param> + /// <param name="setRefreshRateToDisplay"> Set this to false, if another framerate has been specified manually </param> /// <returns></returns> public static float GetSamplingRateFor(MomentForSampling moment, bool setRefreshRateToDisplay = true) { diff --git a/Scripts/LSLMarkerStream.cs b/Scripts/LSLMarkerStream.cs index 3549d681d81cce56c01ddab6983df23a48303c2a..b5dae5fe26af102258ca5cfd4369d9f8a4742d84 100644 --- a/Scripts/LSLMarkerStream.cs +++ b/Scripts/LSLMarkerStream.cs @@ -31,19 +31,19 @@ namespace LSL4Unity.Scripts public void Write(string marker) { _sample[0] = marker; - _lslOutlet.push_sample(_sample); + _lslOutlet.PushSample(_sample); } public void Write(string marker, double customTimeStamp) { _sample[0] = marker; - _lslOutlet.push_sample(_sample, customTimeStamp); + _lslOutlet.PushSample(_sample, customTimeStamp); } public void Write(string marker, float customTimeStamp) { _sample[0] = marker; - _lslOutlet.push_sample(_sample, customTimeStamp); + _lslOutlet.PushSample(_sample, customTimeStamp); } public void WriteBeforeFrameIsDisplayed(string marker) { StartCoroutine(WriteMarkerAfterImageIsRendered(marker)); } diff --git a/Scripts/LSLOutlet.cs b/Scripts/LSLOutlet.cs index 8b59b028fde7343df8d6524819c7ba3fe19f64c6..b6181db1d20f46337a124733905a33f40a540b4e 100644 --- a/Scripts/LSLOutlet.cs +++ b/Scripts/LSLOutlet.cs @@ -5,7 +5,6 @@ namespace LSL4Unity.Scripts { public enum MomentForSampling { Update, FixedUpdate, LateUpdate } - public class LSLOutlet : MonoBehaviour { private liblsl.StreamOutlet _outlet; @@ -18,7 +17,7 @@ namespace LSL4Unity.Scripts private Stopwatch _watch; - // Use this for initialization + /// <summary> Use this for initialization. </summary> private void Start() { _watch = new Stopwatch(); @@ -40,7 +39,7 @@ namespace LSL4Unity.Scripts _watch.Reset(); _watch.Start(); - _outlet.push_sample(_currentSample); + _outlet.PushSample(_currentSample); } } } diff --git a/Scripts/LSLTimeSync.cs b/Scripts/LSLTimeSync.cs index 3b0445bbb52118ee9150fc57c575d791d8f3939d..d94944e6aaeacfa1200185593d5b967b1ddaa12b 100644 --- a/Scripts/LSLTimeSync.cs +++ b/Scripts/LSLTimeSync.cs @@ -18,10 +18,10 @@ namespace LSL4Unity.Scripts private void Awake() { Instance = this; } - private void FixedUpdate() { FixedUpdateTimeStamp = liblsl.local_clock(); } + private void FixedUpdate() { FixedUpdateTimeStamp = liblsl.LocalClock(); } - private void Update() { UpdateTimeStamp = liblsl.local_clock(); } + private void Update() { UpdateTimeStamp = liblsl.LocalClock(); } - private void LateUpdate() { LateUpdateTimeStamp = liblsl.local_clock(); } + private void LateUpdate() { LateUpdateTimeStamp = liblsl.LocalClock(); } } } diff --git a/Scripts/LSLTransformOutlet.cs b/Scripts/LSLTransformOutlet.cs index f8f4167ac03d9e64176f18e8c5164629b0b7ff26..88f13cb86decc9138d4b6f007b22fdacde9d7c59 100644 --- a/Scripts/LSLTransformOutlet.cs +++ b/Scripts/LSLTransformOutlet.cs @@ -4,9 +4,7 @@ using UnityEngine; namespace LSL4Unity.Scripts { - /// <summary> - /// An reusable example of an outlet which provides the orientation and world position of an entity of an Unity Scene to LSL - /// </summary> + /// <summary> An reusable example of an outlet which provides the orientation and world position of an entity of an Unity Scene to LSL. </summary> public class LSLTransformOutlet : MonoBehaviour { private const string UNIQUE_SOURCE_ID_SUFFIX = "63CE5B03731944F6AC30DBB04B451A94"; @@ -18,10 +16,7 @@ namespace LSL4Unity.Scripts private int _channelCount = 0; - /// <summary> - /// Use a array to reduce allocation costs - /// and reuse it for each sampling call - /// </summary> + /// <summary> Use a array to reduce allocation costs and reuse it for each sampling call. </summary> private float[] _currentSample; public Transform SampleSource; @@ -33,9 +28,7 @@ namespace LSL4Unity.Scripts public bool StreamRotationAsEuler = true; public bool StreamPosition = true; - /// <summary> - /// Due to an instable framerate we assume a irregular data rate. - /// </summary> + /// <summary> Due to an instable framerate we assume a irregular data rate. </summary> private const double DATA_RATE = liblsl.IRREGULAR_RATE; private void Awake() @@ -48,20 +41,17 @@ namespace LSL4Unity.Scripts private void Start() { var channelDefinitions = SetupChannels(); - - _channelCount = channelDefinitions.Count; - // initialize the array once + _channelCount = channelDefinitions.Count; _currentSample = new float[_channelCount]; - - _streamInfo = new liblsl.StreamInfo(StreamName, StreamType, _channelCount, DATA_RATE, liblsl.channel_format_t.cf_float32, _uniqueSourceId); + _streamInfo = new liblsl.StreamInfo(StreamName, StreamType, _channelCount, DATA_RATE, liblsl.channel_format_t.cf_float32, _uniqueSourceId); // it's not possible to create a XMLElement before and append it. - liblsl.XMLElement chns = _streamInfo.Desc().append_child("channels"); + liblsl.XMLElement chns = _streamInfo.Desc().AppendChild("channels"); // so this workaround has been introduced. foreach (var def in channelDefinitions) { - chns.append_child("channel").append_child_value("label", def.Label).append_child_value("unit", def.Unit).append_child_value("type", def.Type); + chns.AppendChild("channel").AppendChildValue("label", def.Label).AppendChildValue("unit", def.Unit).AppendChildValue("type", def.Type); } _outlet = new liblsl.StreamOutlet(_streamInfo); @@ -107,7 +97,7 @@ namespace LSL4Unity.Scripts _currentSample[++offset] = position.z; } - _outlet.push_sample(_currentSample, liblsl.local_clock()); + _outlet.PushSample(_currentSample, liblsl.LocalClock()); } diff --git a/Scripts/OV/Inlets.cs b/Scripts/OV/Inlets.cs index ba0174923e50cdd21e1bb20499e72efa0a0a315e..056ccb0c3f40f1b7a7f64d0dc859a52eaba8ecbd 100644 --- a/Scripts/OV/Inlets.cs +++ b/Scripts/OV/Inlets.cs @@ -52,7 +52,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -63,14 +63,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -144,7 +144,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(GetStreamInfoFrom(results)); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); } yield return null; @@ -162,14 +162,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -240,7 +240,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -251,14 +251,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -329,7 +329,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -340,14 +340,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -418,7 +418,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -429,14 +429,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) @@ -507,7 +507,7 @@ namespace LSL4Unity.Scripts.OV _inlet = new liblsl.StreamInlet(results[0]); - _expectedChannels = _inlet.Info().channel_count(); + _expectedChannels = _inlet.Info().ChannelCount(); yield return null; } @@ -518,14 +518,14 @@ namespace LSL4Unity.Scripts.OV try { - double lastTimeStamp = _inlet.pull_sample(_sample, 0.0f); + double lastTimeStamp = _inlet.PullSample(_sample, 0.0f); if (Math.Abs(lastTimeStamp) > Constants.TOLERANCE) { // do not miss the first one found Process(_sample, lastTimeStamp); // pull as long samples are available - while (Math.Abs(lastTimeStamp = _inlet.pull_sample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } + while (Math.Abs(lastTimeStamp = _inlet.PullSample(_sample, 0.0f)) > Constants.TOLERANCE) { Process(_sample, lastTimeStamp); } } } catch (ArgumentException aex) diff --git a/Scripts/Resolver.cs b/Scripts/Resolver.cs index a2b79db1da03045b24479f779381d375bfceb4c2..e5d9dff708902e2de3ba2e50347e754833ebe6fe 100644 --- a/Scripts/Resolver.cs +++ b/Scripts/Resolver.cs @@ -8,10 +8,7 @@ using UnityEngine.EventSystems; namespace LSL4Unity.Scripts { - /// <summary> - /// Encapsulates the lookup logic for LSL streams with an event based appraoch - /// your custom stream inlet implementations could be subscribed to the On - /// </summary> + /// <summary> Encapsulates the lookup logic for LSL streams with an event based appraoch your custom stream inlet implementations could be subscribed to the On. </summary> public class Resolver : MonoBehaviour, IEventSystemHandler { public StreamEvent OnStreamFound = new StreamEvent(); @@ -21,18 +18,18 @@ namespace LSL4Unity.Scripts public List<LSLStreamInfoWrapper> KnownStreams; private liblsl.ContinuousResolver _resolver; - // Use this for initialization + /// <summary> Use this for initialization. </summary> private void Start() { _resolver = new liblsl.ContinuousResolver(ForgetStreamAfter); - StartCoroutine(ResolveContinuously()); } public bool IsStreamAvailable(out LSLStreamInfoWrapper info, string streamName = "", string streamType = "", string hostName = "") { - var result = KnownStreams.Where(i => (streamName == "" || i.Name.Equals(streamName)) && (streamType == "" || i.Type.Equals(streamType)) - && (hostName == "" || i.Type.Equals(hostName))).ToList(); + var result = KnownStreams.Where(i => (streamName.Length == 0 || i.Name.Equals(streamName)) && (streamType.Length == 0 || i.Type.Equals(streamType)) + && (hostName.Length == 0 || i.Type.Equals(hostName))) + .ToList(); if (result.Any()) { @@ -99,11 +96,11 @@ namespace LSL4Unity.Scripts Item = item; Name = item.Name(); Type = item.Type(); - ChannelCount = item.channel_count(); + ChannelCount = item.ChannelCount(); StreamUid = item.Uid(); - SessionId = item.session_id(); - SourceId = item.source_id(); - DataRate = item.nominal_srate(); + SessionId = item.SessionId(); + SourceId = item.SourceId(); + DataRate = item.Sampling(); HostName = item.Hostname(); StreamVersion = item.Version(); }