C API Usage Guide
The C API provides low-level access to Secure LSL functionality.
Full Reference
For complete function signatures and parameters, see the auto-generated C Reference from Doxygen.
Security Query Functions
lsl_security_enabled
Check if security is enabled for a stream.
Parameters:
| Parameter | Type | Description |
|---|---|---|
info |
lsl_streaminfo |
Stream info handle |
Returns: 1 if security is enabled, 0 otherwise.
Example:
lsl_streaminfo info = lsl_create_streaminfo("MyStream", "EEG", 64, 1000, cft_float32, "uid123");
if (lsl_security_enabled(info)) {
printf("Security is enabled\n");
}
lsl_security_fingerprint
Get the security fingerprint for a stream.
Parameters:
| Parameter | Type | Description |
|---|---|---|
info |
lsl_streaminfo |
Stream info handle |
Returns: Fingerprint string (e.g., "SHA256:70:14:e1:b5:...") or empty string if security disabled.
Example:
const char* fingerprint = lsl_security_fingerprint(info);
if (fingerprint && strlen(fingerprint) > 0) {
printf("Fingerprint: %s\n", fingerprint);
}
lsl_local_security_enabled
Check if local security configuration is enabled.
Returns: 1 if local security is configured, 0 otherwise.
Example:
if (lsl_local_security_enabled()) {
printf("This device has security enabled\n");
} else {
printf("Run lsl-keygen to enable security\n");
}
lsl_local_security_fingerprint
Get the local device's public key fingerprint.
Returns: Fingerprint string (e.g., "SHA256:79:8c:1d:7d:...") or empty string if security is not enabled or key is locked.
Example:
const char* fp = lsl_local_security_fingerprint();
if (fp && strlen(fp) > 0) {
printf("Local device fingerprint: %s\n", fp);
}
lsl_security_is_locked
Check if the local security key is locked (passphrase-protected).
Returns: 1 if the key is locked and needs a passphrase, 0 if unlocked or not encrypted.
Example:
if (lsl_security_is_locked()) {
printf("Key is passphrase-protected. Call lsl_security_unlock().\n");
}
lsl_security_unlock
Unlock a passphrase-protected security key.
Parameters:
| Parameter | Type | Description |
|---|---|---|
passphrase |
const char* |
The passphrase to unlock the key |
Returns: 1 on success, 0 on failure (wrong passphrase or key not locked).
Example:
if (lsl_security_is_locked()) {
if (lsl_security_unlock("my_passphrase")) {
printf("Key unlocked successfully\n");
} else {
printf("Wrong passphrase\n");
}
}
Stream Info Extensions
When security is enabled, stream info XML includes a <security> node:
<info>
<name>MyEEG</name>
<type>EEG</type>
<channel_count>64</channel_count>
...
<security>
<enabled>true</enabled>
<public_key>base64_encoded_key</public_key>
<fingerprint>SHA256:70:14:e1:b5:...</fingerprint>
</security>
</info>
Access via standard XML parsing:
Usage Pattern
Creating a Secure Outlet
#include <lsl_c.h>
int main() {
// Check if security is configured locally
if (!lsl_local_security_enabled()) {
fprintf(stderr, "Security not configured. Run lsl-keygen first.\n");
return 1;
}
// Create stream info (security is automatic)
lsl_streaminfo info = lsl_create_streaminfo(
"SecureEEG", // name
"EEG", // type
64, // channels
1000, // sampling rate
cft_float32, // format
"myuid123" // source ID
);
// Verify security is enabled
if (lsl_security_enabled(info)) {
printf("Stream will be encrypted\n");
printf("Fingerprint: %s\n", lsl_security_fingerprint(info));
}
// Create outlet (encryption happens automatically)
lsl_outlet outlet = lsl_create_outlet(info, 0, 360);
// Push samples (they are encrypted transparently)
float sample[64];
while (1) {
// Fill sample with data
lsl_push_sample_f(outlet, sample);
}
lsl_destroy_outlet(outlet);
lsl_destroy_streaminfo(info);
return 0;
}
Creating a Secure Inlet
#include <lsl_c.h>
int main() {
// Resolve secure streams
lsl_streaminfo results[10];
int count = lsl_resolve_byprop(results, 10, "type", "EEG", 0, 5.0);
for (int i = 0; i < count; i++) {
printf("Found: %s\n", lsl_get_name(results[i]));
if (lsl_security_enabled(results[i])) {
printf(" Encrypted: YES\n");
printf(" Fingerprint: %s\n", lsl_security_fingerprint(results[i]));
} else {
printf(" Encrypted: NO\n");
}
}
if (count > 0) {
// Create inlet (decryption happens automatically)
lsl_inlet inlet = lsl_create_inlet(results[0], 360, 0, 1);
// Pull samples (they are decrypted transparently)
float sample[64];
double timestamp;
while (1) {
timestamp = lsl_pull_sample_f(inlet, sample, 64, LSL_FOREVER, NULL);
// Process sample
}
lsl_destroy_inlet(inlet);
}
// Clean up
for (int i = 0; i < count; i++) {
lsl_destroy_streaminfo(results[i]);
}
return 0;
}
Error Handling
Security-related errors are reported through LSL's standard error mechanism:
int32_t error_code;
lsl_pull_sample_f(inlet, sample, 64, 1.0, &error_code);
if (error_code != 0) {
printf("Error: %s\n", lsl_last_error());
}
Common security error messages:
| Error | Cause |
|---|---|
| "Connection refused: security mismatch" | One side has security, other doesn't |
| "Connection refused: outlet does not have security enabled" | Secure inlet, insecure outlet |
| "Connection refused: outlet requires security" | Insecure inlet, secure outlet |
| "Authentication failed" | Key verification failed |
| "Decryption failed" | Data tampering detected |
Thread Safety
All security functions are thread-safe. Multiple threads can:
- Query security status simultaneously
- Create multiple secure outlets/inlets
- Push/pull from different streams concurrently
Next Steps
- C++ API Reference - Object-oriented interface
- Python API Reference - Python bindings
- How Encryption Works - Technical details