@node-webrtc-rust/bindings 0.1.5 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +53 -6
  2. package/index.d.ts +154 -5
  3. package/index.js +33 -5
  4. package/package.json +7 -8
package/README.md CHANGED
@@ -50,15 +50,62 @@ This produces a `node-webrtc-rust.<platform>.node` file in the current directory
50
50
 
51
51
  Set `WEBRTC_DEBUG=1` (or pass `debug: true` in `JsRTCConfiguration`) to emit `[webrtc-debug]` lines from native bindings and the Rust core. See the root README for details.
52
52
 
53
- ## How it works
53
+ ## How native loading works
54
54
 
55
- The `index.js` loader resolves the native binding in this order:
55
+ The root `@node-webrtc-rust/bindings` package ships **no binary** — only `index.js`, `index.d.ts`, and loader logic. The compiled addon lives in separate platform packages listed as **`optionalDependencies`**.
56
56
 
57
- 1. Try requiring the platform-specific npm package (e.g., `@node-webrtc-rust/bindings-darwin-arm64`)
58
- 2. Try loading a local `.node` file matching the current platform (dev builds)
59
- 3. Try loading `node-webrtc-rust.node` (generic local build)
57
+ ### At `npm install`
60
58
 
61
- If none succeed, an error is thrown with instructions.
59
+ The matching platform package is **installed during `npm install`**, not downloaded when your app first runs. Runtime `require()` only loads what is already in `node_modules`.
60
+
61
+ When you install `@node-webrtc-rust/bindings`, npm:
62
+
63
+ 1. Installs the root package (loader only — no `.node`).
64
+ 2. **Attempts each `optionalDependency`** (e.g. `bindings-darwin-arm64`, `bindings-linux-x64-gnu`, …).
65
+ 3. Keeps only packages whose `"os"` / `"cpu"` fields match your machine; others are skipped.
66
+ 4. Does **not** fail the install if a non-matching or unavailable optional package is skipped — that is what “optional” means.
67
+
68
+ On macOS arm64 you typically get:
69
+
70
+ ```text
71
+ node_modules/@node-webrtc-rust/bindings/ ← loader (index.js)
72
+ node_modules/@node-webrtc-rust/bindings-darwin-arm64/
73
+ node-webrtc-rust.darwin-arm64.node ← actual native addon
74
+ ```
75
+
76
+ Each platform package is a thin wrapper: its `"main"` field points directly at the `.node` file, so `require('@node-webrtc-rust/bindings-darwin-arm64')` loads the native module.
77
+
78
+ **When the binary might be missing after install:**
79
+
80
+ | Situation | Result |
81
+ | --- | --- |
82
+ | Normal install on a supported platform | Matching optional package is present |
83
+ | `npm install --omit=optional` | No platform package — runtime fails unless a local `.node` exists |
84
+ | Unsupported OS/arch | No matching optional package |
85
+ | Publish/version mismatch for the optional pkg | Install may succeed; `require()` fails at runtime |
86
+
87
+ ### At runtime (`require('@node-webrtc-rust/bindings')`)
88
+
89
+ `index.js` (auto-generated by NAPI-RS) picks the binary for the current process:
90
+
91
+ 1. **Detect platform** — `process.platform`, `process.arch`, and on Linux whether the libc is musl or glibc (`isMusl()`).
92
+ 2. **Local dev fallback** — if `node-webrtc-rust.<platform>.node` sits next to `index.js` (from `npm run build:local`), `require` that file directly.
93
+ 3. **Published path** — otherwise `require` the matching optional package (e.g. `@node-webrtc-rust/bindings-linux-x64-gnu`).
94
+ 4. **Re-export** — bind NAPI exports (`JsPeerConnection`, `JsConferenceRoom`, …) onto `module.exports`.
95
+
96
+ If both paths fail, Node throws with the underlying `loadError`.
97
+
98
+ ```mermaid
99
+ flowchart TD
100
+ A["require('@node-webrtc-rust/bindings')"] --> B[index.js]
101
+ B --> C{platform + arch + libc?}
102
+ C --> D{local .node beside index.js?}
103
+ D -->|yes| E["require('./node-webrtc-rust.*.node')"]
104
+ D -->|no| F["require('@node-webrtc-rust/bindings-…')"]
105
+ F --> G["platform pkg main → *.node"]
106
+ E --> H[Re-export NAPI symbols]
107
+ G --> H
108
+ ```
62
109
 
63
110
  ### TypeScript note
64
111
 
package/index.d.ts CHANGED
@@ -72,6 +72,17 @@ export interface JsRtcConfiguration {
72
72
  iceTransportPolicy?: string
73
73
  debug?: boolean
74
74
  }
75
+ /** Offer options (W3C `RTCOfferOptions` subset). */
76
+ export interface JsRtcOfferOptions {
77
+ iceRestart?: boolean
78
+ voiceActivityDetection?: boolean
79
+ offerToReceiveAudio?: boolean
80
+ offerToReceiveVideo?: boolean
81
+ }
82
+ /** Answer options (W3C `RTCAnswerOptions` subset). */
83
+ export interface JsRtcAnswerOptions {
84
+ voiceActivityDetection?: boolean
85
+ }
75
86
  /** Session description exposed to JavaScript. */
76
87
  export interface JsRtcSessionDescription {
77
88
  type: string
@@ -92,6 +103,91 @@ export interface JsRtcDataChannelInit {
92
103
  protocol?: string
93
104
  negotiated?: number
94
105
  }
106
+ /** Init options for {@link RTCPeerConnection.addTransceiver}. */
107
+ export interface JsRtcRtpTransceiverInit {
108
+ direction?: string
109
+ }
110
+ export const enum JsEventDeliveryMode {
111
+ Callback = 'callback',
112
+ Stream = 'stream',
113
+ Both = 'both'
114
+ }
115
+ export interface JsEventsConfig {
116
+ mode?: JsEventDeliveryMode
117
+ }
118
+ export interface JsBargeInConfig {
119
+ enabled?: boolean
120
+ useVad?: boolean
121
+ flushTts?: boolean
122
+ }
123
+ export const enum JsVadSampleRate {
124
+ Hz8000 = '8000',
125
+ Hz16000 = '16000'
126
+ }
127
+ export interface JsVadConfig {
128
+ enabled?: boolean
129
+ provider?: string
130
+ threshold?: number
131
+ minSpeechDurationMs?: number
132
+ minSilenceDurationMs?: number
133
+ speechPadMs?: number
134
+ sampleRate?: JsVadSampleRate
135
+ bargeIn?: JsBargeInConfig
136
+ gateStt?: boolean
137
+ gateSttOpenOnPending?: boolean
138
+ sttGateHoldMs?: number
139
+ }
140
+ export const enum JsSttVendor {
141
+ Openai = 'openai',
142
+ Deepgram = 'deepgram',
143
+ Google = 'google',
144
+ Assemblyai = 'assemblyai',
145
+ LocalSherpa = 'local-sherpa',
146
+ Mock = 'mock'
147
+ }
148
+ export const enum JsTtsVendor {
149
+ Openai = 'openai',
150
+ Elevenlabs = 'elevenlabs',
151
+ Google = 'google',
152
+ Cartesia = 'cartesia',
153
+ LocalSherpa = 'local-sherpa',
154
+ Mock = 'mock'
155
+ }
156
+ export interface JsSttConfig {
157
+ provider: JsSttVendor
158
+ model?: string
159
+ modelPath?: string
160
+ language?: string
161
+ apiKey?: string
162
+ }
163
+ export interface JsTtsConfig {
164
+ provider: JsTtsVendor
165
+ model?: string
166
+ modelPath?: string
167
+ voice?: string
168
+ apiKey?: string
169
+ }
170
+ export interface JsVoiceAgentConfig {
171
+ vad?: JsVadConfig
172
+ events?: JsEventsConfig
173
+ stt?: JsSttConfig
174
+ tts?: JsTtsConfig
175
+ }
176
+ export const enum JsSpeechEventType {
177
+ UserSpeakingStart = 'user_speaking_start',
178
+ UserSpeakingEnd = 'user_speaking_end',
179
+ UserSpeechPartial = 'user_speech_partial',
180
+ UserSpeechFinal = 'user_speech_final',
181
+ AgentSpeakingStart = 'agent_speaking_start',
182
+ AgentSpeakingEnd = 'agent_speaking_end',
183
+ BargeIn = 'barge_in',
184
+ Error = 'error'
185
+ }
186
+ export interface JsSpeechEvent {
187
+ eventType: JsSpeechEventType
188
+ text?: string
189
+ error?: string
190
+ }
95
191
  export declare function version(): string
96
192
  /** One conference room with participant and mixing controls. */
97
193
  export declare class JsConferenceRoom {
@@ -146,18 +242,22 @@ export declare class JsRtcDataChannel {
146
242
  bufferedAmount(): Promise<number>
147
243
  send(data: string | Buffer): Promise<void>
148
244
  close(): Promise<void>
245
+ setBufferedAmountLowThreshold(threshold: number): void
246
+ setOnBufferedAmountLow(callback: (...args: any[]) => any): void
149
247
  setOnOpen(callback: (...args: any[]) => any): void
150
248
  setOnMessage(callback: (...args: any[]) => any): void
151
249
  setOnClose(callback: (...args: any[]) => any): void
152
250
  setOnError(callback: (...args: any[]) => any): void
153
251
  }
154
- /** Media stream track exposed to JavaScript (stub). */
252
+ /** Media stream track exposed to JavaScript. */
155
253
  export declare class JsMediaStreamTrack {
156
254
  get id(): string
157
255
  get kind(): string
158
256
  get streamId(): string
159
257
  get enabled(): boolean
160
258
  set enabled(enabled: boolean)
259
+ /** Decodes the next inbound Opus RTP packet to stereo PCM (remote audio only). */
260
+ readSample(): Promise<Buffer>
161
261
  }
162
262
  /** Media stream exposed to JavaScript (stub). */
163
263
  export declare class JsMediaStream {
@@ -172,7 +272,7 @@ export declare class JsLocalAudioTrack {
172
272
  get streamId(): string
173
273
  get enabled(): boolean
174
274
  set enabled(enabled: boolean)
175
- /** Writes a PCM audio frame to the track. */
275
+ /** Writes interleaved stereo PCM; encoded to the negotiated RTP codec before send. */
176
276
  writeSample(data: Buffer, durationMs: number): Promise<void>
177
277
  }
178
278
  /** WebRTC peer connection exposed to JavaScript. */
@@ -182,15 +282,24 @@ export declare class JsPeerConnection {
182
282
  get iceConnectionState(): string
183
283
  get iceGatheringState(): string
184
284
  get signalingState(): string
185
- createOffer(): Promise<JsRtcSessionDescription>
186
- createAnswer(): Promise<JsRtcSessionDescription>
285
+ createOffer(options?: JsRtcOfferOptions | undefined | null): Promise<JsRtcSessionDescription>
286
+ createAnswer(options?: JsRtcAnswerOptions | undefined | null): Promise<JsRtcSessionDescription>
187
287
  setLocalDescription(desc: JsRtcSessionDescription): Promise<void>
188
288
  setRemoteDescription(desc: JsRtcSessionDescription): Promise<void>
189
289
  addIceCandidate(candidate: JsRtcIceCandidate): Promise<void>
190
- addTrack(track: JsLocalAudioTrack): Promise<void>
290
+ addTrack(track: JsLocalAudioTrack): Promise<JsRtpSender>
291
+ removeTrack(sender: JsRtpSender): Promise<void>
292
+ addTransceiver(kind?: string | undefined | null, track?: JsLocalAudioTrack | undefined | null, init?: JsRTCRtpTransceiverInit | undefined | null): Promise<JsRtpTransceiver>
293
+ getTransceivers(): Promise<Array<JsRtpTransceiver>>
294
+ getSenders(): Promise<Array<JsRtpSender>>
295
+ getReceivers(): Promise<Array<JsRtpReceiver>>
191
296
  createDataChannel(label: string, options?: JsRtcDataChannelInit | undefined | null): Promise<JsRtcDataChannel>
192
297
  close(): Promise<void>
193
298
  gatheringComplete(): Promise<void>
299
+ setConfiguration(config: JsRtcConfiguration): Promise<void>
300
+ getConfiguration(): Promise<JsRtcConfiguration>
301
+ restartIce(): Promise<void>
302
+ getStats(): Promise<string>
194
303
  localDescription(): Promise<JsRtcSessionDescription | null>
195
304
  remoteDescription(): Promise<JsRtcSessionDescription | null>
196
305
  setOnIceCandidate(callback: (...args: any[]) => any): void
@@ -198,5 +307,45 @@ export declare class JsPeerConnection {
198
307
  setOnDataChannel(callback: (...args: any[]) => any): void
199
308
  setOnConnectionStateChange(callback: (...args: any[]) => any): void
200
309
  setOnIceConnectionStateChange(callback: (...args: any[]) => any): void
310
+ setOnIceGatheringStateChange(callback: (...args: any[]) => any): void
311
+ setOnSignalingStateChange(callback: (...args: any[]) => any): void
201
312
  setOnNegotiationNeeded(callback: (...args: any[]) => any): void
202
313
  }
314
+ /** RTP receiver leg of an {@link RTCRtpTransceiver}. */
315
+ export declare class JsRtpReceiver {
316
+ get id(): string
317
+ get kind(): string
318
+ }
319
+ /** RTP sender returned from {@link RTCPeerConnection.addTrack}. */
320
+ export declare class JsRtpSender {
321
+ get id(): string
322
+ /** Replaces the outbound audio track without renegotiation. */
323
+ replaceTrack(track?: JsLocalAudioTrack | undefined | null): Promise<void>
324
+ }
325
+ /** Unified Plan transceiver (sender + receiver pair). */
326
+ export declare class JsRtpTransceiver {
327
+ get mid(): string | null
328
+ get direction(): string
329
+ get currentDirection(): string | null
330
+ get kind(): string
331
+ get stopped(): boolean
332
+ get sender(): JsRtpSender
333
+ get receiver(): JsRtpReceiver
334
+ setDirection(direction: string): Promise<void>
335
+ stop(): Promise<void>
336
+ }
337
+ /** Voice agent with VAD, STT/TTS orchestration for one peer connection session. */
338
+ export declare class JsVoiceAgent {
339
+ constructor(config?: JsVoiceAgentConfig | undefined | null)
340
+ /** Attaches outbound local audio track for TTS injection. */
341
+ attach(outboundTrack: JsLocalAudioTrack): Promise<void>
342
+ start(): Promise<void>
343
+ stop(): Promise<void>
344
+ sendTextToTts(text: string): Promise<void>
345
+ flushTts(): Promise<void>
346
+ /** Pull the next speech event for async stream consumption. */
347
+ pullSpeechEvent(): Promise<JsSpeechEvent | null>
348
+ setOnSpeechEvent(callback: (...args: any[]) => any): void
349
+ /** Processes one inbound PCM frame (48 kHz stereo) through VAD/STT. */
350
+ processInboundPcm(data: Buffer, durationMs: number): Promise<void>
351
+ }
package/index.js CHANGED
@@ -310,14 +310,42 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { JsConferenceRoom, JsConferenceServer, JsMuteScope, JsRtcDataChannel, JsMediaStreamTrack, JsMediaStream, JsLocalAudioTrack, JsPeerConnection, version } = nativeBinding
313
+ const {
314
+ JsConferenceRoom,
315
+ JsConferenceServer,
316
+ JsEventDeliveryMode,
317
+ JsLocalAudioTrack,
318
+ JsMediaStream,
319
+ JsMediaStreamTrack,
320
+ JsMuteScope,
321
+ JsPeerConnection,
322
+ JsRtcDataChannel,
323
+ JsRtpReceiver,
324
+ JsRtpSender,
325
+ JsRtpTransceiver,
326
+ JsSpeechEventType,
327
+ JsSttVendor,
328
+ JsTtsVendor,
329
+ JsVadSampleRate,
330
+ JsVoiceAgent,
331
+ version,
332
+ } = nativeBinding
314
333
 
315
334
  module.exports.JsConferenceRoom = JsConferenceRoom
316
335
  module.exports.JsConferenceServer = JsConferenceServer
317
- module.exports.JsMuteScope = JsMuteScope
318
- module.exports.JsRtcDataChannel = JsRtcDataChannel
319
- module.exports.JsMediaStreamTrack = JsMediaStreamTrack
320
- module.exports.JsMediaStream = JsMediaStream
336
+ module.exports.JsEventDeliveryMode = JsEventDeliveryMode
321
337
  module.exports.JsLocalAudioTrack = JsLocalAudioTrack
338
+ module.exports.JsMediaStream = JsMediaStream
339
+ module.exports.JsMediaStreamTrack = JsMediaStreamTrack
340
+ module.exports.JsMuteScope = JsMuteScope
322
341
  module.exports.JsPeerConnection = JsPeerConnection
342
+ module.exports.JsRtcDataChannel = JsRtcDataChannel
343
+ module.exports.JsRtpReceiver = JsRtpReceiver
344
+ module.exports.JsRtpSender = JsRtpSender
345
+ module.exports.JsRtpTransceiver = JsRtpTransceiver
346
+ module.exports.JsSpeechEventType = JsSpeechEventType
347
+ module.exports.JsSttVendor = JsSttVendor
348
+ module.exports.JsTtsVendor = JsTtsVendor
349
+ module.exports.JsVadSampleRate = JsVadSampleRate
350
+ module.exports.JsVoiceAgent = JsVoiceAgent
323
351
  module.exports.version = version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-webrtc-rust/bindings",
3
- "version": "0.1.5",
3
+ "version": "0.3.2",
4
4
  "description": "NAPI-RS native bindings for node-webrtc-rust — WebRTC peer connections, data channels, and conference audio mixing",
5
5
  "keywords": [
6
6
  "webrtc",
@@ -58,13 +58,12 @@
58
58
  "@napi-rs/cli": "^2.18.0"
59
59
  },
60
60
  "optionalDependencies": {
61
- "@node-webrtc-rust/bindings-win32-x64-msvc": "0.1.5",
62
- "@node-webrtc-rust/bindings-darwin-x64": "0.1.5",
63
- "@node-webrtc-rust/bindings-linux-x64-gnu": "0.1.5",
64
- "@node-webrtc-rust/bindings-darwin-arm64": "0.1.5",
65
- "@node-webrtc-rust/bindings-linux-arm64-gnu": "0.1.5",
66
- "@node-webrtc-rust/bindings-linux-arm64-musl": "0.1.4",
67
- "@node-webrtc-rust/bindings-linux-x64-musl": "0.1.5"
61
+ "@node-webrtc-rust/bindings-win32-x64-msvc": "0.3.2",
62
+ "@node-webrtc-rust/bindings-darwin-x64": "0.3.2",
63
+ "@node-webrtc-rust/bindings-linux-x64-gnu": "0.3.2",
64
+ "@node-webrtc-rust/bindings-darwin-arm64": "0.3.2",
65
+ "@node-webrtc-rust/bindings-linux-arm64-gnu": "0.3.2",
66
+ "@node-webrtc-rust/bindings-linux-x64-musl": "0.3.2"
68
67
  },
69
68
  "engines": {
70
69
  "node": ">=18"