@mindfield/capacitor-osc
v1.0.0
Published
Capacitor 7 plugin for Open Sound Control (OSC) — Send and receive OSC messages via UDP
Downloads
49
Maintainers
Readme
@mindfield/capacitor-osc
Capacitor 7 plugin for Open Sound Control (OSC) -- Send and receive OSC messages via UDP on Android and iOS.
Features
- UDP send and receive -- Full bidirectional OSC communication over UDP
- Complete OSC type system -- Int32, Float32, Float64, Int64, String, Blob, True, False, Nil
- Auto-detection -- Numbers are automatically typed as Int32 or Float32; explicit type tags available when you need control
- TypeScript-first -- Full type definitions with JSDoc documentation
- Promise-based API -- Modern async/await interface, no callbacks
- Event-driven receive -- Capacitor listener pattern for incoming messages
- Zero configuration (Android) -- INTERNET permission is auto-added
- Lightweight -- Android uses JavaOSC 0.9 (Maven Central), iOS uses Apple's Network framework (no external dependencies)
Supported Platforms
| Platform | Support | Minimum Version | |----------|---------|-----------------| | Android | Yes | API 23 (Android 6.0) | | iOS | Yes | iOS 14.0 | | Web | No | UDP is not available in browsers |
Installation
npm install @mindfield/capacitor-osc
npx cap syncPlatform Configuration
Android
No extra configuration needed. The INTERNET permission is automatically added by the plugin.
iOS
Add the local network usage description to your Info.plist:
<key>NSLocalNetworkUsageDescription</key>
<string>This app uses the local network to send and receive OSC messages.</string>Quick Start
import { OSC } from '@mindfield/capacitor-osc';
// Send a message
await OSC.send({
host: '192.168.1.100',
port: 9000,
message: { address: '/sensor/eda', args: [3.14, 'hello'] }
});
// Listen for messages
await OSC.startListening({ port: 8000 });
const handle = await OSC.addListener('message', (event) => {
console.log(`${event.address}:`, event.args);
});
// Clean up
handle.remove();
await OSC.stopListening();API Reference
startListening(options)
Start listening for incoming OSC messages on the given UDP port.
startListening(options: StartListeningOptions): Promise<void>| Parameter | Type | Description |
|-----------|------|-------------|
| options.port | number | UDP port to listen on |
Throws an error with code BIND_FAILED if the port is already in use.
await OSC.startListening({ port: 8000 });stopListening()
Stop listening for incoming OSC messages. No-op if not currently listening.
stopListening(): Promise<void>await OSC.stopListening();send(options)
Send an OSC message to the specified host and port.
send(options: SendOptions): Promise<void>| Parameter | Type | Description |
|-----------|------|-------------|
| options.host | string | Target host IP address or hostname |
| options.port | number | Target UDP port |
| options.message | OSCMessage | The OSC message to send |
Throws an error with code SEND_FAILED on network errors.
await OSC.send({
host: '192.168.1.100',
port: 9000,
message: {
address: '/sensor/temperature',
args: [36.5, 'celsius']
}
});getStatus()
Get the current status of the OSC plugin.
getStatus(): Promise<OSCStatusResult>Returns an OSCStatusResult with isListening (boolean) and optionally listeningPort (number).
const status = await OSC.getStatus();
console.log(status.isListening, status.listeningPort);addListener('message', ...)
Listen for incoming OSC messages. Requires startListening() to be called first.
addListener(
eventName: 'message',
listener: (event: OSCMessageEvent) => void
): Promise<PluginListenerHandle>The OSCMessageEvent contains:
| Field | Type | Description |
|-------|------|-------------|
| address | string | OSC address of the received message |
| args | OSCArgumentValue[] | Decoded arguments |
| host | string | Sender IP address (always "" on Android — JavaOSC limitation) |
| port | number | Sender port (always 0 on Android — JavaOSC limitation) |
| timestamp | number | Receive timestamp (ms since epoch) |
const handle = await OSC.addListener('message', (event) => {
if (event.address === '/sensor/eda') {
console.log('EDA value:', event.args[0]);
}
});
// Remove this listener
handle.remove();addListener('error', ...)
Listen for OSC errors (bind failures, send errors, parse errors).
addListener(
eventName: 'error',
listener: (event: OSCErrorEvent) => void
): Promise<PluginListenerHandle>The OSCErrorEvent contains:
| Field | Type | Description |
|-------|------|-------------|
| message | string | Human-readable error description |
| code | string | Error code: BIND_FAILED, SEND_FAILED, or PARSE_ERROR |
await OSC.addListener('error', (event) => {
console.error(`OSC error [${event.code}]: ${event.message}`);
});removeAllListeners()
Remove all listeners for this plugin.
removeAllListeners(): Promise<void>await OSC.removeAllListeners();Type Reference
OSCTypedArg
Explicit type tag for OSC arguments. Use when auto-detection is insufficient.
interface OSCTypedArg {
type: 'i' | 'f' | 'd' | 'h' | 's' | 'b' | 'T' | 'F' | 'N';
value?: number | string | boolean | null;
}OSCArgumentValue
A union type representing any OSC argument:
type OSCArgumentValue = number | string | boolean | null | OSCTypedArg;OSCMessage
interface OSCMessage {
address: string; // OSC address pattern, e.g. "/sensor/eda"
args?: OSCArgumentValue[]; // Arguments to include
}OSCMessageEvent
interface OSCMessageEvent {
address: string; // OSC address of the received message
args: OSCArgumentValue[]; // Decoded arguments
host: string; // Sender IP address
port: number; // Sender port
timestamp: number; // Receive timestamp (ms since epoch)
}OSCErrorEvent
interface OSCErrorEvent {
message: string; // Human-readable error description
code: 'BIND_FAILED' | 'SEND_FAILED' | 'PARSE_ERROR';
}StartListeningOptions
interface StartListeningOptions {
port: number; // UDP port to listen on
}SendOptions
interface SendOptions {
host: string; // Target host IP or hostname
port: number; // Target UDP port
message: OSCMessage; // The OSC message to send
}OSCStatusResult
interface OSCStatusResult {
isListening: boolean; // Whether currently listening
listeningPort?: number; // Port being listened on, if listening
}OSC Type System
The plugin supports the full OSC 1.0 type system. Primitive JS values are auto-detected; use OSCTypedArg for explicit control.
| JS Value | OSC Type | Tag | Notes |
|----------|----------|-----|-------|
| 42 (integer) | Int32 | i | Auto-detected via Number.isInteger() |
| 3.14 (float) | Float32 | f | Auto-detected (non-integer number) |
| 'hello' | String | s | |
| true | True | T | |
| false | False | F | |
| null | Nil | N | |
| { type: 'i', value: 42 } | Int32 | i | Explicit |
| { type: 'f', value: 1.0 } | Float32 | f | Explicit -- forces float even for integer values |
| { type: 'd', value: 3.14159265358979 } | Float64 | d | Explicit double precision |
| { type: 'h', value: 9007199254740992 } | Int64 | h | Explicit 64-bit integer |
| { type: 's', value: 'text' } | String | s | Explicit |
| { type: 'b', value: 'SGVsbG8=' } | Blob | b | Base64-encoded binary data |
| { type: 'T' } | True | T | Explicit (value ignored) |
| { type: 'F' } | False | F | Explicit (value ignored) |
| { type: 'N' } | Nil | N | Explicit (value ignored) |
When to Use Explicit Types
Auto-detection works well for most cases. Use explicit OSCTypedArg when:
- You need
Float32for an integer value (e.g.,{ type: 'f', value: 1 }sends1.0as float) - You need
Float64double precision (not available via auto-detection) - You need
Int64for large integers (not available via auto-detection) - You need to send binary
Blobdata
Migration from cordova-plugin-osc
| cordova-plugin-osc | @mindfield/capacitor-osc | Notes |
|---------------------|--------------------------|-------|
| new OSC() | import { OSC } | Singleton, no instantiation needed |
| osc.startListening(port, cb) | await OSC.startListening({ port }) | Promise-based, no callback |
| osc.addListener(addr, cb) | await OSC.addListener('message', cb) | Global listener; filter by address in JS |
| osc.send({...}) | await OSC.send({...}) | Similar structure, Promise return |
| osc.stopListening() | await OSC.stopListening() | |
| osc.close() | await OSC.stopListening() | Combined into one method |
| Callback error handling | OSC.addListener('error', cb) | Dedicated error event |
Use Cases
- Biofeedback -- Stream eSense sensor data (EDA, temperature) to Max/MSP, Pure Data, or custom visualizers
- VJing and Visuals -- Control TouchDesigner, Resolume, or Processing sketches from a mobile device
- Music Production -- Send control data to Ableton Live, SuperCollider, Reaktor, or any DAW with OSC support
- Interactive Installations -- Bridge mobile sensors to desktop applications for real-time audience interaction
- Research -- Forward physiological measurements to lab software (LabVIEW, OpenViBE, custom tools)
Contributing
See CONTRIBUTING.md for development setup and contribution guidelines.
License
MIT -- Mindfield Biosystems Ltd.
