node-labstreaminglayer
Version:
Node.js bindings for Lab Streaming Layer (LSL)
171 lines • 6.1 kB
JavaScript
import { lsl_resolve_all, lsl_resolve_byprop, lsl_resolve_bypred, lsl_create_continuous_resolver, lsl_create_continuous_resolver_byprop, lsl_create_continuous_resolver_bypred, lsl_destroy_continuous_resolver, lsl_resolver_results } from './lib/index.js';
import { StreamInfo } from './streamInfo.js';
import { FOREVER } from './util.js';
/**
* Find all streams on the network.
* @param waitTime Time to wait for streams in seconds (default: 1.0)
* @returns Array of StreamInfo objects
*/
export function resolveStreams(waitTime = 1.0) {
// Create buffer for stream info pointers
const bufferSize = 1024;
const buffer = new Array(bufferSize).fill(null);
// Resolve streams
const numFound = lsl_resolve_all(buffer, bufferSize, waitTime);
// Convert to StreamInfo objects
const results = [];
for (let i = 0; i < numFound; i++) {
const handle = buffer[i];
if (handle) {
results.push(new StreamInfo('', '', 0, 0, 0, '', handle));
}
}
return results;
}
/**
* Find streams by a specific property.
* @param prop Property name to match (e.g., 'name', 'type')
* @param value Property value to match
* @param minimum Minimum number of streams to find
* @param timeout Timeout in seconds
* @returns Array of StreamInfo objects
*/
export function resolveByProp(prop, value, minimum = 1, timeout = FOREVER) {
// Create buffer for stream info pointers
const bufferSize = 1024;
const buffer = new Array(bufferSize).fill(null);
// Resolve streams by property
const numFound = lsl_resolve_byprop(buffer, bufferSize, prop, value, minimum, timeout);
// Convert to StreamInfo objects
const results = [];
for (let i = 0; i < numFound; i++) {
const handle = buffer[i];
if (handle) {
results.push(new StreamInfo('', '', 0, 0, 0, '', handle));
}
}
return results;
}
/**
* Find streams by an XPath predicate.
* @param predicate XPath predicate string (e.g., "name='MyStream' and type='EEG'")
* @param minimum Minimum number of streams to find
* @param timeout Timeout in seconds
* @returns Array of StreamInfo objects
*/
export function resolveByPred(predicate, minimum = 1, timeout = FOREVER) {
// Create buffer for stream info pointers
const bufferSize = 1024;
const buffer = new Array(bufferSize).fill(null);
// Resolve streams by predicate
const numFound = lsl_resolve_bypred(buffer, bufferSize, predicate, minimum, timeout);
// Convert to StreamInfo objects
const results = [];
for (let i = 0; i < numFound; i++) {
const handle = buffer[i];
if (handle) {
results.push(new StreamInfo('', '', 0, 0, 0, '', handle));
}
}
return results;
}
// Legacy compatibility function
export function resolveStream(...args) {
if (args.length === 0) {
return resolveStreams();
}
else if (typeof args[0] === 'number') {
return resolveStreams(args[0]);
}
else if (typeof args[0] === 'string') {
if (args.length === 1) {
return resolveByPred(args[0]);
}
else if (typeof args[1] === 'number') {
return resolveByPred(args[0], args[1]);
}
else {
if (args.length === 2) {
return resolveByProp(args[0], args[1]);
}
else {
return resolveByProp(args[0], args[1], args[2]);
}
}
}
throw new Error('Invalid arguments for resolveStream');
}
// FinalizationRegistry for automatic cleanup
const resolverRegistry = new FinalizationRegistry((obj) => {
try {
lsl_destroy_continuous_resolver(obj);
}
catch (e) {
// Silently ignore cleanup errors
}
});
/**
* Continuously resolves streams in the background.
* Useful for monitoring streams that may appear and disappear.
*/
export class ContinuousResolver {
obj; // Pointer to the continuous resolver object
constructor(prop, value, pred, forgetAfter = 5.0) {
if (pred !== undefined) {
if (prop !== undefined || value !== undefined) {
throw new Error('You can only either pass the prop/value argument or the pred argument, but not both.');
}
this.obj = lsl_create_continuous_resolver_bypred(pred, forgetAfter);
}
else if (prop !== undefined && value !== undefined) {
this.obj = lsl_create_continuous_resolver_byprop(prop, value, forgetAfter);
}
else if (prop !== undefined || value !== undefined) {
throw new Error('If prop is specified, then value must be specified too, and vice versa.');
}
else {
this.obj = lsl_create_continuous_resolver(forgetAfter);
}
if (!this.obj) {
throw new Error('Could not create continuous resolver.');
}
// Register for automatic cleanup
resolverRegistry.register(this, this.obj, this);
}
/**
* Destroy the resolver and free resources.
*/
destroy() {
if (this.obj) {
try {
resolverRegistry.unregister(this);
lsl_destroy_continuous_resolver(this.obj);
}
catch (e) {
// Silently ignore errors during destruction
}
this.obj = null;
}
}
/**
* Get the current list of resolved streams.
* @returns Array of StreamInfo objects
*/
results() {
// Create buffer for stream info pointers
const bufferSize = 1024;
const buffer = new Array(bufferSize).fill(null);
// Get resolver results
const numFound = lsl_resolver_results(this.obj, buffer, bufferSize);
// Convert to StreamInfo objects
const results = [];
for (let i = 0; i < numFound; i++) {
const handle = buffer[i];
if (handle) {
results.push(new StreamInfo('', '', 0, 0, 0, '', handle));
}
}
return results;
}
}
//# sourceMappingURL=resolver.js.map