@agentdance/node-webrtc 1.0.0

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 (66) hide show
  1. package/dist/data-channel.d.ts +33 -0
  2. package/dist/data-channel.d.ts.map +1 -0
  3. package/dist/data-channel.js +138 -0
  4. package/dist/data-channel.js.map +1 -0
  5. package/dist/ice-candidate.d.ts +30 -0
  6. package/dist/ice-candidate.d.ts.map +1 -0
  7. package/dist/ice-candidate.js +78 -0
  8. package/dist/ice-candidate.js.map +1 -0
  9. package/dist/index.d.ts +9 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +9 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/internal/peer-internals.d.ts +55 -0
  14. package/dist/internal/peer-internals.d.ts.map +1 -0
  15. package/dist/internal/peer-internals.js +412 -0
  16. package/dist/internal/peer-internals.js.map +1 -0
  17. package/dist/internal/sdp-factory.d.ts +9 -0
  18. package/dist/internal/sdp-factory.d.ts.map +1 -0
  19. package/dist/internal/sdp-factory.js +58 -0
  20. package/dist/internal/sdp-factory.js.map +1 -0
  21. package/dist/internal/sdp-parser.d.ts +15 -0
  22. package/dist/internal/sdp-parser.d.ts.map +1 -0
  23. package/dist/internal/sdp-parser.js +70 -0
  24. package/dist/internal/sdp-parser.js.map +1 -0
  25. package/dist/peer-connection.d.ts +72 -0
  26. package/dist/peer-connection.d.ts.map +1 -0
  27. package/dist/peer-connection.js +198 -0
  28. package/dist/peer-connection.js.map +1 -0
  29. package/dist/rtp-receiver.d.ts +28 -0
  30. package/dist/rtp-receiver.d.ts.map +1 -0
  31. package/dist/rtp-receiver.js +39 -0
  32. package/dist/rtp-receiver.js.map +1 -0
  33. package/dist/rtp-sender.d.ts +29 -0
  34. package/dist/rtp-sender.d.ts.map +1 -0
  35. package/dist/rtp-sender.js +58 -0
  36. package/dist/rtp-sender.js.map +1 -0
  37. package/dist/rtp-transceiver.d.ts +25 -0
  38. package/dist/rtp-transceiver.d.ts.map +1 -0
  39. package/dist/rtp-transceiver.js +28 -0
  40. package/dist/rtp-transceiver.js.map +1 -0
  41. package/dist/session-description.d.ts +8 -0
  42. package/dist/session-description.d.ts.map +1 -0
  43. package/dist/session-description.js +12 -0
  44. package/dist/session-description.js.map +1 -0
  45. package/dist/stats.d.ts +16 -0
  46. package/dist/stats.d.ts.map +1 -0
  47. package/dist/stats.js +22 -0
  48. package/dist/stats.js.map +1 -0
  49. package/dist/types.d.ts +113 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +2 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +68 -0
  54. package/src/data-channel.ts +165 -0
  55. package/src/ice-candidate.ts +91 -0
  56. package/src/index.ts +8 -0
  57. package/src/internal/peer-internals.ts +477 -0
  58. package/src/internal/sdp-factory.ts +81 -0
  59. package/src/internal/sdp-parser.ts +69 -0
  60. package/src/peer-connection.ts +253 -0
  61. package/src/rtp-receiver.ts +51 -0
  62. package/src/rtp-sender.ts +77 -0
  63. package/src/rtp-transceiver.ts +40 -0
  64. package/src/session-description.ts +15 -0
  65. package/src/stats.ts +35 -0
  66. package/src/types.ts +156 -0
@@ -0,0 +1,412 @@
1
+ /**
2
+ * PeerInternals - The glue layer connecting ICE, DTLS, SRTP, SCTP and SDP
3
+ * for the RTCPeerConnection implementation.
4
+ *
5
+ * Connection flow:
6
+ * 1. createOffer/createAnswer → SDP generation
7
+ * 2. setLocalDescription → start ICE gathering
8
+ * 3. setRemoteDescription → parse remote SDP, set remote ICE params
9
+ * 4. addIceCandidate → feed candidates to ICE agent
10
+ * 5. ICE connects → start DTLS handshake
11
+ * 6. DTLS connects → extract SRTP keying material + start SCTP
12
+ * 7. SCTP connects → DataChannels available
13
+ */
14
+ import { EventEmitter } from 'events';
15
+ import { RTCDataChannel as WebRTCDataChannel } from '../data-channel.js';
16
+ import { RTCStatsReportImpl } from '../stats.js';
17
+ export class PeerInternals extends EventEmitter {
18
+ _pc;
19
+ _config;
20
+ iceAgent;
21
+ dtlsTransport;
22
+ sctpAssociation;
23
+ localCertificate;
24
+ _localSdp;
25
+ _remoteSdp;
26
+ _remoteFingerprint = null;
27
+ _remoteSctpPort = null;
28
+ _iceRole = 'controlling';
29
+ _dtlsRole = 'client';
30
+ _pendingDataChannels = [];
31
+ _stunServers = [];
32
+ constructor(config, pc) {
33
+ super();
34
+ this._config = config;
35
+ this._pc = pc;
36
+ // Parse ICE server URLs
37
+ for (const server of config.iceServers ?? []) {
38
+ const urls = Array.isArray(server.urls) ? server.urls : [server.urls];
39
+ for (const url of urls) {
40
+ const match = url.match(/^stun:(.+):(\d+)$/);
41
+ if (match) {
42
+ this._stunServers.push({ host: match[1], port: parseInt(match[2], 10) });
43
+ }
44
+ }
45
+ }
46
+ }
47
+ async createOffer(_options) {
48
+ const { generateSdpOffer } = await import('./sdp-factory.js');
49
+ await this._ensureIceAgent();
50
+ await this._ensureCertificate();
51
+ const sdp = await generateSdpOffer(this.iceAgent, this._config, this.localCertificate);
52
+ this._localSdp = sdp;
53
+ return { type: 'offer', sdp };
54
+ }
55
+ async createAnswer(_options) {
56
+ const { generateSdpAnswer } = await import('./sdp-factory.js');
57
+ await this._ensureIceAgent();
58
+ await this._ensureCertificate();
59
+ const sdp = await generateSdpAnswer(this.iceAgent, this._remoteSdp, this._config, this.localCertificate);
60
+ this._localSdp = sdp;
61
+ return { type: 'answer', sdp };
62
+ }
63
+ async setLocalDescription(desc) {
64
+ this._localSdp = desc.sdp;
65
+ await this._ensureIceAgent();
66
+ if (desc.type === 'offer') {
67
+ this._iceRole = 'controlling';
68
+ this._dtlsRole = 'client';
69
+ }
70
+ else if (desc.type === 'answer') {
71
+ if (desc.sdp.includes('a=setup:passive')) {
72
+ this._dtlsRole = 'server';
73
+ }
74
+ }
75
+ this._pc._updateIceGatheringState('gathering');
76
+ await this.iceAgent.gather();
77
+ // If remote description already set, start connectivity now (answerer case)
78
+ if (this._remoteSdp && desc.type !== 'offer') {
79
+ this._startConnectivity(this._remoteFingerprint, this._remoteSctpPort).catch(() => { });
80
+ }
81
+ }
82
+ async setRemoteDescription(desc) {
83
+ this._remoteSdp = desc.sdp;
84
+ // Set ICE/DTLS role before creating the ICE agent
85
+ if (desc.type === 'offer') {
86
+ this._iceRole = 'controlled';
87
+ // DTLS role will be determined by local SDP (a=setup:active/passive)
88
+ }
89
+ else if (desc.type === 'answer') {
90
+ // Offerer path: determine DTLS role from the remote answer's a=setup attribute.
91
+ // If remote answered 'active' they are DTLS client → we must be server.
92
+ // If remote answered 'passive' they are DTLS server → we must be client.
93
+ const remoteSetup = desc.sdp.match(/a=setup:(\w+)/)?.[1];
94
+ if (remoteSetup === 'active') {
95
+ this._dtlsRole = 'server';
96
+ }
97
+ else if (remoteSetup === 'passive') {
98
+ this._dtlsRole = 'client';
99
+ }
100
+ }
101
+ await this._ensureIceAgent();
102
+ const { parseIceParameters, parseDtlsFingerprint, parseSctpPort, parseCandidatesFromSdp } = await import('./sdp-parser.js');
103
+ const iceParams = parseIceParameters(desc.sdp);
104
+ const fingerprint = parseDtlsFingerprint(desc.sdp);
105
+ const sctpPort = parseSctpPort(desc.sdp);
106
+ // Cache for use by setLocalDescription (answerer flow)
107
+ this._remoteFingerprint = fingerprint;
108
+ this._remoteSctpPort = sctpPort;
109
+ if (iceParams) {
110
+ this.iceAgent.setRemoteParameters(iceParams);
111
+ }
112
+ const candidates = parseCandidatesFromSdp(desc.sdp);
113
+ for (const candidate of candidates) {
114
+ this.iceAgent.addRemoteCandidate(candidate);
115
+ }
116
+ if (desc.sdp.includes('a=end-of-candidates')) {
117
+ this.iceAgent.remoteGatheringComplete();
118
+ }
119
+ if (this._localSdp) {
120
+ this._startConnectivity(fingerprint, sctpPort).catch(() => { });
121
+ }
122
+ }
123
+ async addIceCandidate(init) {
124
+ if (!this.iceAgent)
125
+ return;
126
+ const { parseCandidatesFromSdp } = await import('./sdp-parser.js');
127
+ // Wrap the candidate string in a minimal SDP-like format for the parser
128
+ const candidateStr = init.candidate ?? '';
129
+ if (!candidateStr)
130
+ return;
131
+ const fakeSdp = `a=candidate:${candidateStr.replace(/^candidate:/, '')}`;
132
+ const [candidate] = parseCandidatesFromSdp(fakeSdp);
133
+ if (candidate) {
134
+ this.iceAgent.addRemoteCandidate(candidate);
135
+ }
136
+ }
137
+ openDataChannel(channel) {
138
+ if (this.sctpAssociation?.state === 'connected') {
139
+ this._openDataChannelOnSctp(channel);
140
+ }
141
+ else {
142
+ this._pendingDataChannels.push(channel);
143
+ }
144
+ }
145
+ restartIce() {
146
+ if (!this.iceAgent)
147
+ return;
148
+ // Reset ICE credentials and re-gather — forces re-negotiation
149
+ this.iceAgent.restart().catch(() => { });
150
+ this._pc._updateIceConnectionState('checking');
151
+ // Signal that new local candidates will be available
152
+ this._pc._updateIceGatheringState('gathering');
153
+ // Trigger re-negotiation so the new ICE credentials are exchanged
154
+ this._pc.emit('negotiationneeded');
155
+ }
156
+ close() {
157
+ this.sctpAssociation?.close();
158
+ this.dtlsTransport?.close();
159
+ this.iceAgent?.close();
160
+ }
161
+ async getStats() {
162
+ const stats = new Map();
163
+ const now = Date.now();
164
+ // Candidate pair stats
165
+ const pair = this.iceAgent?.getSelectedPair();
166
+ if (pair) {
167
+ const localId = `local-candidate-${pair.local.foundation}`;
168
+ const remoteId = `remote-candidate-${pair.remote.foundation}`;
169
+ stats.set('candidate-pair-0', {
170
+ id: 'candidate-pair-0',
171
+ type: 'candidate-pair',
172
+ timestamp: now,
173
+ localCandidateId: localId,
174
+ remoteCandidateId: remoteId,
175
+ state: 'succeeded',
176
+ nominated: true,
177
+ bytesSent: 0,
178
+ bytesReceived: 0,
179
+ totalRoundTripTime: 0,
180
+ });
181
+ stats.set(localId, {
182
+ id: localId,
183
+ type: 'local-candidate',
184
+ timestamp: now,
185
+ candidateType: pair.local.type,
186
+ ip: pair.local.address,
187
+ port: pair.local.port,
188
+ protocol: pair.local.transport,
189
+ priority: pair.local.priority,
190
+ });
191
+ stats.set(remoteId, {
192
+ id: remoteId,
193
+ type: 'remote-candidate',
194
+ timestamp: now,
195
+ candidateType: pair.remote.type,
196
+ ip: pair.remote.address,
197
+ port: pair.remote.port,
198
+ protocol: pair.remote.transport,
199
+ priority: pair.remote.priority,
200
+ });
201
+ }
202
+ // Transport stats
203
+ if (this.dtlsTransport) {
204
+ stats.set('transport-0', {
205
+ id: 'transport-0',
206
+ type: 'transport',
207
+ timestamp: now,
208
+ dtlsState: this.dtlsTransport.getState(),
209
+ selectedCandidatePairId: pair ? 'candidate-pair-0' : undefined,
210
+ });
211
+ }
212
+ // Data channel stats (one per channel)
213
+ if (this.sctpAssociation) {
214
+ let dcIndex = 0;
215
+ for (const [, sctpCh] of this.sctpAssociation._channels) {
216
+ const dcId = `data-channel-${dcIndex++}`;
217
+ stats.set(dcId, {
218
+ id: dcId,
219
+ type: 'data-channel',
220
+ timestamp: now,
221
+ label: sctpCh.label,
222
+ protocol: sctpCh.protocol,
223
+ dataChannelIdentifier: sctpCh.id,
224
+ state: sctpCh.state,
225
+ messagesSent: 0,
226
+ bytesSent: 0,
227
+ messagesReceived: 0,
228
+ bytesReceived: 0,
229
+ });
230
+ }
231
+ }
232
+ // Peer connection stats
233
+ stats.set('peer-connection', {
234
+ id: 'peer-connection',
235
+ type: 'peer-connection',
236
+ timestamp: now,
237
+ dataChannelsOpened: this.sctpAssociation
238
+ ? this.sctpAssociation._channels.size
239
+ : 0,
240
+ dataChannelsClosed: 0,
241
+ });
242
+ return new RTCStatsReportImpl(stats);
243
+ }
244
+ async _ensureCertificate() {
245
+ if (this.localCertificate)
246
+ return;
247
+ const { generateSelfSignedCertificate } = await import('@agentdance/node-webrtc-dtls');
248
+ this.localCertificate = generateSelfSignedCertificate();
249
+ }
250
+ async _ensureIceAgent() {
251
+ if (this.iceAgent)
252
+ return;
253
+ const { IceAgent, serializeCandidateAttribute } = await import('@agentdance/node-webrtc-ice');
254
+ this.iceAgent = new IceAgent({
255
+ stunServers: this._stunServers,
256
+ role: this._iceRole,
257
+ });
258
+ this.iceAgent.on('local-candidate', (candidate) => {
259
+ this._pc.emit('icecandidate', {
260
+ candidate: 'candidate:' + serializeCandidateAttribute(candidate),
261
+ sdpMid: '0',
262
+ sdpMLineIndex: 0,
263
+ });
264
+ });
265
+ this.iceAgent.on('gathering-complete', () => {
266
+ this._pc._updateIceGatheringState('complete');
267
+ this._pc.emit('icecandidate', null);
268
+ });
269
+ this.iceAgent.on('connection-state', (state) => {
270
+ const stateMap = {
271
+ new: 'new',
272
+ checking: 'checking',
273
+ connected: 'connected',
274
+ completed: 'completed',
275
+ failed: 'failed',
276
+ disconnected: 'disconnected',
277
+ closed: 'closed',
278
+ };
279
+ const mapped = stateMap[state] ?? 'new';
280
+ this._pc._updateIceConnectionState(mapped);
281
+ // Connection recovery: when ICE reconnects after a disconnect/failure,
282
+ // restore peer connection state
283
+ if (state === 'connected' || state === 'completed') {
284
+ if (this._pc.connectionState === 'disconnected' || this._pc.connectionState === 'failed') {
285
+ this._pc._updateConnectionState('connected');
286
+ }
287
+ }
288
+ else if (state === 'disconnected') {
289
+ if (this._pc.connectionState === 'connected') {
290
+ this._pc._updateConnectionState('disconnected');
291
+ }
292
+ }
293
+ else if (state === 'failed') {
294
+ this._pc._updateConnectionState('failed');
295
+ }
296
+ });
297
+ this.iceAgent.on('connected', async () => {
298
+ this._pc._updateConnectionState('connecting');
299
+ });
300
+ }
301
+ async _startConnectivity(remoteFingerprint, sctpPort) {
302
+ if (!this.iceAgent)
303
+ return;
304
+ if (this.dtlsTransport)
305
+ return; // Guard against double-start
306
+ this._pc._updateIceConnectionState('checking');
307
+ // Pre-create DTLS transport and wire ICE→DTLS BEFORE ICE connects,
308
+ // so DTLS handshake packets are not lost when the remote sends first.
309
+ const { DtlsTransport } = await import('@agentdance/node-webrtc-dtls');
310
+ const dtlsOpts = {
311
+ role: this._dtlsRole,
312
+ ...(this.localCertificate ? { certificate: this.localCertificate } : {}),
313
+ };
314
+ if (remoteFingerprint !== null) {
315
+ dtlsOpts.remoteFingerprint = remoteFingerprint;
316
+ }
317
+ this.dtlsTransport = new DtlsTransport(dtlsOpts);
318
+ // Wire ICE → DTLS (packets received from remote)
319
+ this.iceAgent.on('data', (data) => {
320
+ this.dtlsTransport.handleIncoming(data);
321
+ });
322
+ // Wire DTLS → ICE (packets to send to remote)
323
+ this.dtlsTransport.setSendCallback((data) => {
324
+ this.iceAgent.send(data);
325
+ });
326
+ // Use event-driven approach: start DTLS when ICE nominates a pair.
327
+ // This handles the race condition where connect() fails early in trickle ICE.
328
+ const dtlsTransport = this.dtlsTransport;
329
+ const startDtls = async () => {
330
+ try {
331
+ console.log('[PeerInternals] starting DTLS...');
332
+ await dtlsTransport.start();
333
+ console.log('[PeerInternals] DTLS connected, starting SCTP...');
334
+ if (sctpPort !== null) {
335
+ await this._startSctp(sctpPort);
336
+ console.log('[PeerInternals] SCTP connected!');
337
+ }
338
+ this._pc._updateConnectionState('connected');
339
+ console.log('[PeerInternals] connectionState=connected');
340
+ }
341
+ catch (e) {
342
+ console.error('[PeerInternals] DTLS/SCTP failed:', e);
343
+ this._pc._updateIceConnectionState('failed');
344
+ this._pc._updateConnectionState('failed');
345
+ }
346
+ };
347
+ // Start ICE connectivity checks
348
+ try {
349
+ await this.iceAgent.connect();
350
+ // ICE is connected — start DTLS handshake
351
+ await startDtls();
352
+ }
353
+ catch {
354
+ // connect() may fail early due to trickle ICE timing.
355
+ // The iceAgent 'connected' event will fire when ICE actually connects.
356
+ // Register one-time handler.
357
+ this.iceAgent.once('connected', () => {
358
+ startDtls().catch(() => { });
359
+ });
360
+ }
361
+ }
362
+ async _startSctp(remotePort) {
363
+ const { SctpAssociation } = await import('@agentdance/node-webrtc-sctp');
364
+ this.sctpAssociation = new SctpAssociation({
365
+ localPort: 5000,
366
+ remotePort,
367
+ role: this._dtlsRole === 'client' ? 'client' : 'server',
368
+ });
369
+ // Wire DTLS ↔ SCTP
370
+ this.dtlsTransport.on('data', (data) => {
371
+ this.sctpAssociation.handleIncoming(data);
372
+ });
373
+ this.sctpAssociation.setSendCallback((data) => {
374
+ this.dtlsTransport.send(data);
375
+ });
376
+ // Handle incoming data channels
377
+ this.sctpAssociation.on('datachannel', (sctpChannel) => {
378
+ const channel = new WebRTCDataChannel(sctpChannel.label, {
379
+ ordered: sctpChannel.ordered,
380
+ id: sctpChannel.id,
381
+ protocol: sctpChannel.protocol,
382
+ }, sctpChannel);
383
+ this._pc.emit('datachannel', channel);
384
+ });
385
+ await this.sctpAssociation.connect();
386
+ // Open any pending data channels
387
+ for (const dc of this._pendingDataChannels) {
388
+ this._openDataChannelOnSctp(dc);
389
+ }
390
+ this._pendingDataChannels.length = 0;
391
+ }
392
+ _openDataChannelOnSctp(channel) {
393
+ if (!this.sctpAssociation)
394
+ return;
395
+ const opts = {
396
+ label: channel.label,
397
+ ordered: channel.ordered,
398
+ protocol: channel.protocol,
399
+ negotiated: channel.negotiated,
400
+ };
401
+ if (channel.maxRetransmits !== null)
402
+ opts.maxRetransmits = channel.maxRetransmits;
403
+ if (channel.maxPacketLifeTime !== null)
404
+ opts.maxPacketLifeTime = channel.maxPacketLifeTime;
405
+ // For negotiated channels, id must be provided; for auto channels, let SCTP assign
406
+ if (channel.id !== null)
407
+ opts.id = channel.id;
408
+ const sctpChannel = this.sctpAssociation.createDataChannel(opts);
409
+ channel._bindSctpChannel(sctpChannel);
410
+ }
411
+ }
412
+ //# sourceMappingURL=peer-internals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer-internals.js","sourceRoot":"","sources":["../../src/internal/peer-internals.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * SDP generation for offer/answer
3
+ */
4
+ import type { IceAgent } from '@agentdance/node-webrtc-ice';
5
+ import type { DtlsCertificate } from '@agentdance/node-webrtc-dtls';
6
+ import type { RTCConfiguration } from '../types.js';
7
+ export declare function generateSdpOffer(iceAgent: IceAgent, config: Required<RTCConfiguration>, certificate: DtlsCertificate): Promise<string>;
8
+ export declare function generateSdpAnswer(iceAgent: IceAgent, remoteSdp: string, config: Required<RTCConfiguration>, certificate: DtlsCertificate): Promise<string>;
9
+ //# sourceMappingURL=sdp-factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdp-factory.d.ts","sourceRoot":"","sources":["../../src/internal/sdp-factory.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAClC,WAAW,EAAE,eAAe,GAC3B,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAClC,WAAW,EAAE,eAAe,GAC3B,OAAO,CAAC,MAAM,CAAC,CAkCjB"}
@@ -0,0 +1,58 @@
1
+ import crypto from 'node:crypto';
2
+ export async function generateSdpOffer(iceAgent, config, certificate) {
3
+ const localParams = iceAgent.localParameters;
4
+ const sessionId = crypto.randomBytes(8).readBigUInt64BE(0).toString();
5
+ const lines = [
6
+ 'v=0',
7
+ `o=- ${sessionId} 1 IN IP4 127.0.0.1`,
8
+ 's=-',
9
+ 't=0 0',
10
+ 'a=group:BUNDLE 0',
11
+ 'a=extmap-allow-mixed',
12
+ 'a=msid-semantic: WMS',
13
+ // Data channel media section
14
+ 'm=application 9 UDP/DTLS/SCTP webrtc-datachannel',
15
+ 'c=IN IP4 0.0.0.0',
16
+ `a=ice-ufrag:${localParams.usernameFragment}`,
17
+ `a=ice-pwd:${localParams.password}`,
18
+ 'a=ice-options:trickle',
19
+ `a=fingerprint:sha-256 ${certificate.fingerprint.value}`,
20
+ 'a=setup:actpass',
21
+ 'a=mid:0',
22
+ 'a=sctp-port:5000',
23
+ 'a=max-message-size:262144',
24
+ ];
25
+ return lines.join('\r\n') + '\r\n';
26
+ }
27
+ export async function generateSdpAnswer(iceAgent, remoteSdp, config, certificate) {
28
+ const localParams = iceAgent.localParameters;
29
+ // Determine DTLS setup role per RFC 5763 §5:
30
+ // remote=actpass → we pick active (we become DTLS client)
31
+ // remote=active → we must be passive (we become DTLS server)
32
+ // remote=passive → we must be active (we become DTLS client)
33
+ const remoteSetup = remoteSdp.match(/a=setup:(\w+)/)?.[1] ?? 'actpass';
34
+ const localSetup = remoteSetup === 'actpass' ? 'active' :
35
+ remoteSetup === 'active' ? 'passive' : 'active';
36
+ const sessionId = Math.floor(Math.random() * 1e15).toString();
37
+ const lines = [
38
+ 'v=0',
39
+ `o=- ${sessionId} 1 IN IP4 127.0.0.1`,
40
+ 's=-',
41
+ 't=0 0',
42
+ 'a=group:BUNDLE 0',
43
+ 'a=extmap-allow-mixed',
44
+ 'a=msid-semantic: WMS',
45
+ 'm=application 9 UDP/DTLS/SCTP webrtc-datachannel',
46
+ 'c=IN IP4 0.0.0.0',
47
+ `a=ice-ufrag:${localParams.usernameFragment}`,
48
+ `a=ice-pwd:${localParams.password}`,
49
+ 'a=ice-options:trickle',
50
+ `a=fingerprint:sha-256 ${certificate.fingerprint.value}`,
51
+ `a=setup:${localSetup}`,
52
+ 'a=mid:0',
53
+ 'a=sctp-port:5000',
54
+ 'a=max-message-size:262144',
55
+ ];
56
+ return lines.join('\r\n') + '\r\n';
57
+ }
58
+ //# sourceMappingURL=sdp-factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdp-factory.js","sourceRoot":"","sources":["../../src/internal/sdp-factory.ts"],"names":[],"mappings":"AAMA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAkB,EAClB,MAAkC,EAClC,WAA4B;IAE5B,MAAM,WAAW,GAAG,QAAQ,CAAC,eAAe,CAAC;IAE7C,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEtE,MAAM,KAAK,GAAa;QACtB,KAAK;QACL,OAAO,SAAS,qBAAqB;QACrC,KAAK;QACL,OAAO;QACP,kBAAkB;QAClB,sBAAsB;QACtB,sBAAsB;QACtB,6BAA6B;QAC7B,kDAAkD;QAClD,kBAAkB;QAClB,eAAe,WAAW,CAAC,gBAAgB,EAAE;QAC7C,aAAa,WAAW,CAAC,QAAQ,EAAE;QACnC,uBAAuB;QACvB,yBAAyB,WAAW,CAAC,WAAW,CAAC,KAAK,EAAE;QACxD,iBAAiB;QACjB,SAAS;QACT,kBAAkB;QAClB,2BAA2B;KAC5B,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAkB,EAClB,SAAiB,EACjB,MAAkC,EAClC,WAA4B;IAE5B,MAAM,WAAW,GAAG,QAAQ,CAAC,eAAe,CAAC;IAE7C,6CAA6C;IAC7C,4DAA4D;IAC5D,gEAAgE;IAChE,gEAAgE;IAChE,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IACvE,MAAM,UAAU,GAAG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtC,WAAW,KAAK,QAAQ,CAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEpE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAE9D,MAAM,KAAK,GAAa;QACtB,KAAK;QACL,OAAO,SAAS,qBAAqB;QACrC,KAAK;QACL,OAAO;QACP,kBAAkB;QAClB,sBAAsB;QACtB,sBAAsB;QACtB,kDAAkD;QAClD,kBAAkB;QAClB,eAAe,WAAW,CAAC,gBAAgB,EAAE;QAC7C,aAAa,WAAW,CAAC,QAAQ,EAAE;QACnC,uBAAuB;QACvB,yBAAyB,WAAW,CAAC,WAAW,CAAC,KAAK,EAAE;QACxD,WAAW,UAAU,EAAE;QACvB,SAAS;QACT,kBAAkB;QAClB,2BAA2B;KAC5B,CAAC;IAEF,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;AACrC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Parse ICE/DTLS/SCTP parameters from SDP strings
3
+ */
4
+ export interface ParsedIceParameters {
5
+ usernameFragment: string;
6
+ password: string;
7
+ }
8
+ export declare function parseIceParameters(sdp: string): ParsedIceParameters | null;
9
+ export declare function parseDtlsFingerprint(sdp: string): {
10
+ algorithm: string;
11
+ value: string;
12
+ } | null;
13
+ export declare function parseSctpPort(sdp: string): number | null;
14
+ export declare function parseCandidatesFromSdp(sdp: string): import('@agentdance/node-webrtc-ice').IceCandidate[];
15
+ //# sourceMappingURL=sdp-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdp-parser.d.ts","sourceRoot":"","sources":["../../src/internal/sdp-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAQ1E;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI7F;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIxD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,6BAA6B,EAAE,YAAY,EAAE,CAWxG"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Parse ICE/DTLS/SCTP parameters from SDP strings
3
+ */
4
+ export function parseIceParameters(sdp) {
5
+ const ufragMatch = sdp.match(/a=ice-ufrag:(\S+)/);
6
+ const pwdMatch = sdp.match(/a=ice-pwd:(\S+)/);
7
+ if (!ufragMatch || !pwdMatch)
8
+ return null;
9
+ return {
10
+ usernameFragment: ufragMatch[1],
11
+ password: pwdMatch[1],
12
+ };
13
+ }
14
+ export function parseDtlsFingerprint(sdp) {
15
+ const match = sdp.match(/a=fingerprint:(\S+)\s+(\S+)/);
16
+ if (!match)
17
+ return null;
18
+ return { algorithm: match[1], value: match[2] };
19
+ }
20
+ export function parseSctpPort(sdp) {
21
+ const match = sdp.match(/a=sctp-port:(\d+)/);
22
+ if (!match)
23
+ return null;
24
+ return parseInt(match[1], 10);
25
+ }
26
+ export function parseCandidatesFromSdp(sdp) {
27
+ const candidates = [];
28
+ const lines = sdp.split(/\r?\n/);
29
+ for (const line of lines) {
30
+ const match = line.match(/^a=candidate:(.+)$/);
31
+ if (match) {
32
+ const candidate = parseCandidateLine(match[1]);
33
+ if (candidate)
34
+ candidates.push(candidate);
35
+ }
36
+ }
37
+ return candidates;
38
+ }
39
+ function parseCandidateLine(value) {
40
+ const parts = value.split(' ');
41
+ if (parts.length < 8)
42
+ return null;
43
+ const [foundation, componentStr, transport, priorityStr, address, portStr, , type, ...rest] = parts;
44
+ const candidate = {
45
+ foundation: foundation ?? '',
46
+ component: (componentStr === '1' ? 1 : 2),
47
+ transport: (transport?.toLowerCase() ?? 'udp'),
48
+ priority: parseInt(priorityStr ?? '0', 10),
49
+ address: address ?? '',
50
+ port: parseInt(portStr ?? '0', 10),
51
+ type: (type ?? 'host'),
52
+ };
53
+ // Parse extensions
54
+ for (let i = 0; i < rest.length - 1; i += 2) {
55
+ const key = rest[i];
56
+ const val = rest[i + 1];
57
+ if (key === 'raddr' && val !== undefined)
58
+ candidate.relatedAddress = val;
59
+ else if (key === 'rport' && val !== undefined)
60
+ candidate.relatedPort = parseInt(val, 10);
61
+ else if (key === 'generation' && val !== undefined)
62
+ candidate.generation = parseInt(val, 10);
63
+ else if (key === 'ufrag' && val !== undefined)
64
+ candidate.ufrag = val;
65
+ else if (key === 'network-id' && val !== undefined)
66
+ candidate.networkId = parseInt(val, 10);
67
+ }
68
+ return candidate;
69
+ }
70
+ //# sourceMappingURL=sdp-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdp-parser.js","sourceRoot":"","sources":["../../src/internal/sdp-parser.ts"],"names":[],"mappings":"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"}