@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.
- package/README.md +53 -6
- package/index.d.ts +154 -5
- package/index.js +33 -5
- 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
|
|
53
|
+
## How native loading works
|
|
54
54
|
|
|
55
|
-
The `index.js` loader
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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<
|
|
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 {
|
|
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.
|
|
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.
|
|
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.
|
|
62
|
-
"@node-webrtc-rust/bindings-darwin-x64": "0.
|
|
63
|
-
"@node-webrtc-rust/bindings-linux-x64-gnu": "0.
|
|
64
|
-
"@node-webrtc-rust/bindings-darwin-arm64": "0.
|
|
65
|
-
"@node-webrtc-rust/bindings-linux-arm64-gnu": "0.
|
|
66
|
-
"@node-webrtc-rust/bindings-linux-
|
|
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"
|