Skip to content

Commit 0b35dba

Browse files
cboulaytstenner
authored andcommitted
Add support for more precision on buffer lengths; necessary for high bandwidth streams where 1 sec is too long.
1 parent dba0513 commit 0b35dba

File tree

11 files changed

+96
-29
lines changed

11 files changed

+96
-29
lines changed

include/lsl/common.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,21 @@ typedef enum {
150150
_lsl_error_code_maxval = 0x7f000000
151151
} lsl_error_code_t;
152152

153+
/// Flags for outlet_ex and inlet_ex
154+
typedef enum {
155+
/// Keep legacy behavior: max_buffered / max_buflen is in seconds; use asynch transfer.
156+
transp_default = 0,
157+
158+
/// The supplied max_buf value is in samples.
159+
transp_bufsize_samples = 1,
160+
161+
/// The supplied max_buf should be scaled by 0.001.
162+
transp_bufsize_thousandths = 2,
163+
164+
// prevent compilers from assuming an instance fits in a single byte
165+
_lsl_transport_options_maxval = 0x7f000000
166+
} lsl_transport_options_t;
167+
153168
/// Return an explanation for the last error
154169
extern LIBLSL_C_API const char *lsl_last_error(void);
155170

include/lsl/inlet.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
* @return A newly created lsl_inlet handle or NULL in the event that an error occurred.
4040
*/
4141
extern LIBLSL_C_API lsl_inlet lsl_create_inlet(lsl_streaminfo info, int32_t max_buflen, int32_t max_chunklen, int32_t recover);
42+
/** @copydoc lsl_create_inlet()
43+
* @param flags An integer that is the result of bitwise OR'ing one or more options from
44+
* #lsl_transport_options_t together (e.g., #transp_bufsize_samples)
45+
*/
46+
extern LIBLSL_C_API lsl_inlet lsl_create_inlet_ex(lsl_streaminfo info, int32_t max_buflen,
47+
int32_t max_chunklen, int32_t recover, lsl_transport_options_t flags);
4248

4349
/**
4450
* Destructor.

include/lsl/outlet.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
* @return A newly created lsl_outlet handle or NULL in the event that an error occurred.
3535
*/
3636
extern LIBLSL_C_API lsl_outlet lsl_create_outlet(lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered);
37+
/** @copydoc lsl_create_outlet()
38+
* @param flags An integer that is the result of bitwise OR'ing one or more options from
39+
* #lsl_transport_options_t together (e.g., #transp_bufsize_samples|#transp_bufsize_thousandths)
40+
*/
41+
extern LIBLSL_C_API lsl_outlet lsl_create_outlet_ex(
42+
lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered, lsl_transport_options_t flags);
3743

3844
/**
3945
* Destroy an outlet.
@@ -93,7 +99,8 @@ extern LIBLSL_C_API int32_t lsl_push_sample_vtp(lsl_outlet out, const void *data
9399
/** @copybrief lsl_push_sample_ftp
94100
* @see lsl_push_sample_ftp
95101
* @param out The lsl_outlet object through which to push the data.
96-
* @param data A pointer to values to push. The number of values pointed to must be no less than the number of channels in the sample.
102+
* @param data A pointer to values to push. The number of values pointed to must be no less than the
103+
* number of channels in the sample.
97104
* @param lengths A pointer the number of elements to push for each channel (string lengths).
98105
*/
99106
extern LIBLSL_C_API int32_t lsl_push_sample_buf(lsl_outlet out, const char **data, const uint32_t *lengths);

include/lsl_cpp.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,11 @@ class stream_outlet {
396396
* @param max_buffered Optionally the maximum amount of data to buffer (in seconds if there is a
397397
* nominal sampling rate, otherwise x100 in samples). The default is 6 minutes of data.
398398
*/
399-
stream_outlet(const stream_info &info, int32_t chunk_size = 0, int32_t max_buffered = 360)
400-
: channel_count(info.channel_count()),
401-
sample_rate(info.nominal_srate()),
402-
obj(lsl_create_outlet(info.handle().get(), chunk_size, max_buffered), &lsl_destroy_outlet) {}
399+
stream_outlet(const stream_info &info, int32_t chunk_size = 0, int32_t max_buffered = 360,
400+
lsl_transport_options_t flags = transp_default)
401+
: channel_count(info.channel_count()), sample_rate(info.nominal_srate()),
402+
obj(lsl_create_outlet_ex(info.handle().get(), chunk_size, max_buffered, flags),
403+
&lsl_destroy_outlet) {}
403404

404405
// ========================================
405406
// === Pushing a sample into the outlet ===
@@ -900,9 +901,10 @@ class stream_inlet {
900901
* lsl::lost_error if the stream's source is lost (e.g., due to an app or computer crash).
901902
*/
902903
stream_inlet(const stream_info &info, int32_t max_buflen = 360, int32_t max_chunklen = 0,
903-
bool recover = true)
904+
bool recover = true, lsl_transport_options_t flags = transp_default)
904905
: channel_count(info.channel_count()),
905-
obj(lsl_create_inlet(info.handle().get(), max_buflen, max_chunklen, recover), &lsl_destroy_inlet) {}
906+
obj(lsl_create_inlet_ex(info.handle().get(), max_buflen, max_chunklen, recover, flags),
907+
&lsl_destroy_inlet) {}
906908

907909
/// Return a shared pointer to pass to C-API functions that aren't wrapped yet
908910
///

src/lsl_inlet_c.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@ extern "C" {
1414

1515
using namespace lsl;
1616

17+
LIBLSL_C_API lsl_inlet lsl_create_inlet_ex(lsl_streaminfo info, int32_t max_buflen,
18+
int32_t max_chunklen, int32_t recover, lsl_transport_options_t flags) {
19+
try {
20+
int32_t buf_samples = info->calc_transport_buf_samples(max_buflen, flags);
21+
return create_object_noexcept<stream_inlet_impl>(
22+
*info, buf_samples, max_chunklen, recover != 0);
23+
}
24+
LSLCATCHANDSTORE(nullptr, std::invalid_argument, lsl_argument_error);
25+
return nullptr;
26+
}
1727
LIBLSL_C_API lsl_inlet lsl_create_inlet(
1828
lsl_streaminfo info, int32_t max_buflen, int32_t max_chunklen, int32_t recover) {
19-
return create_object_noexcept<stream_inlet_impl>(*info,
20-
(info->nominal_srate() ? (int)(info->nominal_srate() * max_buflen) : max_buflen * 100) + 1,
21-
max_chunklen, recover != 0);
29+
return lsl_create_inlet_ex(info, max_buflen, max_chunklen, recover, transp_default);
2230
}
2331

2432
LIBLSL_C_API void lsl_destroy_inlet(lsl_inlet in) {

src/lsl_outlet_c.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ extern "C" {
1515
using namespace lsl;
1616

1717
// boilerplate wrapper code
18+
LIBLSL_C_API lsl_outlet lsl_create_outlet_ex(
19+
lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered, lsl_transport_options_t flags) {
20+
return create_object_noexcept<stream_outlet_impl>(*info, chunk_size, max_buffered, flags);
21+
}
22+
1823
LIBLSL_C_API lsl_outlet lsl_create_outlet(
1924
lsl_streaminfo info, int32_t chunk_size, int32_t max_buffered) {
20-
double buftime = info->nominal_srate();
21-
if (buftime <= 0) buftime = 100;
22-
return create_object_noexcept<stream_outlet_impl>(
23-
*info, chunk_size, static_cast<int>(buftime * max_buffered));
25+
return lsl_create_outlet_ex(info, chunk_size, max_buffered, transp_default);
2426
}
2527

2628
LIBLSL_C_API void lsl_destroy_outlet(lsl_outlet out) {

src/stream_info_impl.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,24 @@ int stream_info_impl::channel_bytes() const {
244244
xml_node stream_info_impl::desc() { return doc_.child("info").child("desc"); }
245245
xml_node stream_info_impl::desc() const { return doc_.child("info").child("desc"); }
246246

247+
uint32_t lsl::stream_info_impl::calc_transport_buf_samples(
248+
int32_t requested_len, lsl_transport_options_t flags) const {
249+
if ((flags & transp_bufsize_samples) && (flags & transp_bufsize_thousandths))
250+
throw std::invalid_argument(
251+
"transp_bufsize_samples and transp_bufsize_thousandths are mutually exclusive");
252+
253+
int32_t buf_samples;
254+
if (flags & transp_bufsize_samples)
255+
buf_samples = requested_len;
256+
else if (nominal_srate() == LSL_IRREGULAR_RATE)
257+
buf_samples = requested_len * 100;
258+
else
259+
buf_samples = nominal_srate() * requested_len;
260+
if (flags & transp_bufsize_thousandths) buf_samples /= 1000;
261+
buf_samples = (buf_samples > 0) ? buf_samples : 1;
262+
return buf_samples;
263+
}
264+
247265
void stream_info_impl::version(int v) {
248266
version_ = v;
249267
doc_.child("info").child("version").first_child().set_value(to_string(version_ / 100.).c_str());

src/stream_info_impl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ class stream_info_impl {
221221
pugi::xml_node desc();
222222
pugi::xml_node desc() const;
223223

224+
/// helper function to calculate the buffer size in samples for inlets and outlets
225+
uint32_t calc_transport_buf_samples(int32_t requested_len, lsl_transport_options_t flags) const;
226+
224227
protected:
225228
/// Create and assign the XML DOM structure based on the class fields.
226229
void write_xml(pugi::xml_document &doc);

src/stream_outlet_impl.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,17 @@
1111

1212
namespace lsl {
1313

14-
stream_outlet_impl::stream_outlet_impl(
15-
const stream_info_impl &info, int32_t chunk_size, int32_t max_capacity)
14+
stream_outlet_impl::stream_outlet_impl(const stream_info_impl &info, int32_t chunk_size,
15+
int32_t requested_bufsize, lsl_transport_options_t flags)
1616
: sample_factory_(std::make_shared<factory>(info.channel_format(), info.channel_count(),
1717
static_cast<uint32_t>(
1818
info.nominal_srate()
1919
? info.nominal_srate() * api_config::get_instance()->outlet_buffer_reserve_ms() /
2020
1000
2121
: api_config::get_instance()->outlet_buffer_reserve_samples()))),
22-
chunk_size_(chunk_size), info_(std::make_shared<stream_info_impl>(info)),
23-
send_buffer_(std::make_shared<send_buffer>(max_capacity)),
22+
chunk_size_(info.calc_transport_buf_samples(requested_bufsize, flags)),
23+
info_(std::make_shared<stream_info_impl>(info)),
24+
send_buffer_(std::make_shared<send_buffer>(chunk_size_)),
2425
io_ctx_data_(std::make_shared<asio::io_context>(1)),
2526
io_ctx_service_(std::make_shared<asio::io_context>(1)) {
2627
ensure_lsl_initialized();

src/stream_outlet_impl.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ class stream_outlet_impl {
3232
* @param chunk_size The preferred chunk size, in samples, at which data shall be transmitted
3333
* over the network. Can be selectively overridden by the inlet. If 0 (=default), the chunk size
3434
* is determined by the pushthrough flag in push_sample or push_chunk.
35-
* @param max_capacity The maximum number of samples buffered for unresponsive receivers. If
36-
* more samples get pushed, the oldest will be dropped. The default is sufficient to hold a bit
37-
* more than 15 minutes of data at 512Hz, while consuming not more than ca. 512MB of RAM.
35+
* @param requested_size The maximum number of seconds/samples buffered for unresponsive
36+
* receivers. If more samples get pushed, the oldest will be dropped. The default is sufficient
37+
* to hold a bit more than 15 minutes of data at 512Hz, while consuming not more than ca. 512MB
38+
* of RAM. Depends on `flags` as calculated in `stream_info_impl::calc_transport_buf_samples()`
39+
* @param flags Bitwise-OR'd flags from lsl_transport_options_t
3840
*/
39-
stream_outlet_impl(
40-
const stream_info_impl &info, int32_t chunk_size = 0, int32_t max_capacity = 512000);
41+
stream_outlet_impl(const stream_info_impl &info, int32_t chunk_size = 0,
42+
int32_t requested_bufsize = 900, lsl_transport_options_t flags = transp_default);
4143

4244
/**
4345
* Destructor.

0 commit comments

Comments
 (0)