1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "common.h"
#include "resolver_impl.h"
#include "api_config.h"
#include <boost/chrono/system_clocks.hpp>
#include <iostream>
// === Implementation of the free-standing functions in lsl_c.h ===
using namespace lsl;
using std::string;
using std::vector;
extern "C" {
#include "../include/lsl_c.h"
/**
* Get the protocol version.
*/
LIBLSL_C_API int32_t lsl_protocol_version() { return api_config::get_instance()->use_protocol_version(); }
/**
* Get the library version.
*/
LIBLSL_C_API int32_t lsl_library_version() { return LSL_LIBRARY_VERSION; }
/** Get a string containing library information */
LIBLSL_C_API const char *lsl_library_info() {
#ifdef LSL_LIBRARY_INFO_STR
return LSL_LIBRARY_INFO_STR;
#else
return "Unknown (not set by build system)";
#endif
}
/**
* 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.
*/
LIBLSL_C_API double lsl_local_clock() {
return lslboost::chrono::nanoseconds(lslboost::chrono::high_resolution_clock::now().time_since_epoch()).count()/1000000000.0;
}
/**
* 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 buffer A user-allocated buffer to hold the resolve results.
* Note: it is the user's responsibility to either destroy the resulting streaminfo
* objects or to pass them back to the LSL during during creation of an inlet.
* @param buffer_elements The user-provided buffer length.
* @param wait_time The waiting time for the operation, in seconds, to search for streams.
* Warning: If this is too short (<0.5s) only a subset (or none) of the
* outlets that are present on the network may be returned.
* @return The number of results written into the buffer (never more than the provided # of slots) or a negative number if an
* error has occurred (values corresponding to lsl_error_code_t).
*/
LIBLSL_C_API int32_t lsl_resolve_all(lsl_streaminfo *buffer, uint32_t buffer_elements, double wait_time) {
try {
// create a new resolver
resolver_impl resolver;
// invoke it (our only constraint is that the session id shall be the same as ours)
string sess_id = api_config::get_instance()->session_id();
std::vector<stream_info_impl> tmp = resolver.resolve_oneshot((string("session_id='") += sess_id) += "'",0,wait_time);
// allocate new stream_info_impl's and assign to the buffer
uint32_t result = buffer_elements<tmp.size() ? buffer_elements : (uint32_t)tmp.size();
for (uint32_t k=0;k<result;k++)
buffer[k] = (lsl_streaminfo)new stream_info_impl(tmp[k]);
return result;
} catch(std::exception &e) {
std::cerr << "Error during resolve_all: " << e.what() << std::endl;
return lsl_internal_error;
}
}
/**
* Resolve all streams with a given value for a 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 buffer A user-allocated buffer to hold the resolve results.
* Note: it is the user's responsibility to either destroy the resulting streaminfo
* objects or to pass them back to the LSL during during creation of an inlet.
* @param buffer_elements The user-provided buffer length.
* @param prop The streaminfo 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 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 The number of results written into the buffer (never more than the provided # of slots) or a negative number if an
* error has occurred (values corresponding to lsl_error_code_t).
*/
LIBLSL_C_API int32_t lsl_resolve_byprop(lsl_streaminfo *buffer, uint32_t buffer_elements, const char *prop, const char *value, int32_t minimum, double timeout) {
try {
// create a new resolver
resolver_impl resolver;
// build a new query.
std::ostringstream os; os << "session_id='" << api_config::get_instance()->session_id() << "' and " << prop << "='" << value << "'";
// invoke it
std::vector<stream_info_impl> tmp = resolver.resolve_oneshot(os.str(),minimum,timeout);
// allocate new stream_info_impl's and assign to the buffer
uint32_t result = buffer_elements<tmp.size() ? buffer_elements : (uint32_t)tmp.size();
for (uint32_t k=0;k<result;k++)
buffer[k] = (lsl_streaminfo)new stream_info_impl(tmp[k]);
return result;
} catch(std::exception &e) {
std::cerr << "Error during resolve_byprop: " << e.what() << std::endl;
return lsl_internal_error;
}
}
/**
* 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 buffer A user-allocated buffer to hold the resolve results.
* Note: it is the user's responsibility to either destroy the resulting streaminfo
* objects or to pass them back to the LSL during during creation of an inlet.
* @param buffer_elements The user-provided buffer length.
* @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 The number of results written into the buffer (never more than the provided # of slots) or a negative number if an
* error has occurred (values corresponding to lsl_error_code_t).
*/
LIBLSL_C_API int32_t lsl_resolve_bypred(lsl_streaminfo *buffer, uint32_t buffer_elements, const char *pred, int32_t minimum, double timeout) {
try {
// create a new resolver
resolver_impl resolver;
// build a new query.
std::ostringstream os; os << "session_id='" << api_config::get_instance()->session_id() << "' and " << pred;
// invoke it
std::vector<stream_info_impl> tmp = resolver.resolve_oneshot(os.str(),minimum,timeout);
// allocate new stream_info_impl's and assign to the buffer
uint32_t result = buffer_elements<tmp.size() ? buffer_elements : (uint32_t)tmp.size();
for (uint32_t k=0;k<result;k++)
buffer[k] = (lsl_streaminfo)new stream_info_impl(tmp[k]);
return result;
} catch(std::exception &e) {
std::cerr << "Error during resolve_bypred: " << e.what() << std::endl;
return lsl_internal_error;
}
}
/**
* Deallocate a string that has been transferred to the application.
* The only use case is to deallocate the contents of string-valued samples
* received from LSL in an application where no free() method is available
* (e.g., in some scripting languages).
*/
LIBLSL_C_API void lsl_destroy_string(char *s) {
if (s)
free(s);
}
}