UNPKG

node-labstreaminglayer

Version:
171 lines 6.1 kB
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