node-rtc-connection 1.0.12 → 1.0.15

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 CHANGED
@@ -1,29 +1,16 @@
1
- # node-rtc-connection - WebRTC DataChannels for Node.js
1
+ # NodeRTC
2
2
 
3
- [![npm version](https://badge.fury.io/js/node-rtc-connection.svg)](https://www.npmjs.com/package/node-rtc-connection)
4
- [![Node.js CI](https://github.com/nmhung1210/nodertc/workflows/Test/badge.svg)](https://github.com/nmhung1210/nodertc/actions)
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
-
7
- A production-ready WebRTC DataChannel implementation for Node.js with **real networking**, **STUN/TURN support**, **MESSAGE-INTEGRITY authentication**, and **optional encryption**. Built with pure Node.js - no native dependencies required.
8
-
9
- ## Overview
10
-
11
- node-rtc-connection provides WebRTC-style peer-to-peer data connections using Node.js built-in modules. It supports NAT traversal via STUN/TURN servers with full RFC 5766 MESSAGE-INTEGRITY authentication, optional TLS encryption, and works across the internet for most network configurations.
3
+ A Node.js WebRTC implementation with full ICE/STUN/TURN support for real peer-to-peer networking.
12
4
 
13
5
  ## Features
14
6
 
15
- - ✅ **RTCPeerConnection** - Full peer connection lifecycle
16
- - ✅ **RTCDataChannel** - Bidirectional data channels
17
- - ✅ **STUN Support** - NAT traversal with public STUN servers
18
- - ✅ **TURN Support** - Relay through TURN servers (RFC 5766)
19
- - ✅ **MESSAGE-INTEGRITY** - Full authentication support for TURN
20
- - ✅ **ICE Candidates** - Host, server reflexive, and relay candidates
21
- - ✅ **TLS Encryption** - Optional secure connections
22
- - ✅ **Real Networking** - TCP/UDP with actual peer-to-peer communication
23
- - ✅ **Event-based API** - Built on Node.js EventEmitter
24
- - ✅ **Zero Dependencies** - Pure Node.js, no native modules
25
- - ✅ **Docker TURN Server** - Included for testing and development
26
- - ❌ **No Media Support** - DataChannel only (no audio/video)
7
+ - ✅ **Real Network Transport**: Uses actual UDP/TCP sockets for true peer-to-peer connections
8
+ - ✅ **ICE Support**: Full Interactive Connectivity Establishment with candidate gathering
9
+ - ✅ **STUN Support**: NAT traversal with server reflexive candidates
10
+ - ✅ **TURN Support**: Relay candidates for restrictive network environments
11
+ - ✅ **Data Channels**: Reliable and ordered data channels for P2P communication
12
+ - ✅ **DTLS/SCTP**: Secure transport with DTLS encryption and SCTP for data channels
13
+ - ✅ **Standards Compliant**: Follows WebRTC and ICE specifications
27
14
 
28
15
  ## Installation
29
16
 
@@ -33,395 +20,474 @@ npm install node-rtc-connection
33
20
 
34
21
  ## Quick Start
35
22
 
36
- ### Basic Usage
23
+ ### Basic Local Connection (No STUN/TURN)
37
24
 
38
25
  ```javascript
39
- const { createPeerConnection } = require('node-rtc-connection');
26
+ const { RTCPeerConnection } = require('node-rtc-connection');
40
27
 
41
- // Create peer connection
42
- const pc = createPeerConnection();
28
+ // Create two peer connections
29
+ const pc1 = new RTCPeerConnection({ iceServers: [] });
30
+ const pc2 = new RTCPeerConnection({ iceServers: [] });
43
31
 
44
- // Create a data channel
45
- const channel = pc.createDataChannel('myChannel');
32
+ // Set up data channel on peer 1
33
+ const channel = pc1.createDataChannel('chat');
46
34
 
47
35
  channel.on('open', () => {
48
- console.log('DataChannel opened');
49
- channel.send('Hello, peer!');
36
+ console.log('Channel opened!');
37
+ channel.send('Hello from Peer 1!');
50
38
  });
51
39
 
52
40
  channel.on('message', (event) => {
53
- console.log('Received:', event.data.toString());
41
+ console.log('Received:', event.data);
42
+ });
43
+
44
+ // Peer 2 receives data channel
45
+ pc2.on('datachannel', (event) => {
46
+ const channel = event.channel;
47
+
48
+ channel.on('message', (event) => {
49
+ console.log('Received:', event.data);
50
+ channel.send('Hello from Peer 2!');
51
+ });
52
+ });
53
+
54
+ // Exchange ICE candidates
55
+ pc1.on('icecandidate', (e) => {
56
+ if (e.candidate) pc2.addIceCandidate(e.candidate);
57
+ });
58
+
59
+ pc2.on('icecandidate', (e) => {
60
+ if (e.candidate) pc1.addIceCandidate(e.candidate);
54
61
  });
55
62
 
56
- // Handle ICE candidates
63
+ // Signaling (offer/answer exchange)
64
+ async function connect() {
65
+ const offer = await pc1.createOffer();
66
+ await pc1.setLocalDescription(offer);
67
+
68
+ await pc2.setRemoteDescription(offer);
69
+ const answer = await pc2.createAnswer();
70
+ await pc2.setLocalDescription(answer);
71
+
72
+ await pc1.setRemoteDescription(answer);
73
+ }
74
+
75
+ connect();
76
+ ```
77
+
78
+ ### With STUN Server (NAT Traversal)
79
+
80
+ ```javascript
81
+ const { RTCPeerConnection } = require('node-rtc-connection');
82
+
83
+ const config = {
84
+ iceServers: [
85
+ { urls: 'stun:stun.l.google.com:19302' }
86
+ ]
87
+ };
88
+
89
+ const pc = new RTCPeerConnection(config);
90
+
91
+ // Listen for gathered ICE candidates
57
92
  pc.on('icecandidate', (event) => {
58
93
  if (event.candidate) {
59
- // Send to remote peer via signaling
94
+ console.log('ICE Candidate:', event.candidate.candidate);
95
+ // Send to remote peer via your signaling channel
60
96
  }
61
97
  });
62
98
 
63
- // Create and set local description
99
+ // Create offer and start ICE gathering
64
100
  const offer = await pc.createOffer();
65
101
  await pc.setLocalDescription(offer);
66
102
  ```
67
103
 
68
- ### With STUN and TURN (Recommended)
104
+ ### With TURN Server (Relay Support)
69
105
 
70
106
  ```javascript
71
- const { createPeerConnection } = require('node-rtc-connection');
107
+ const { RTCPeerConnection } = require('node-rtc-connection');
72
108
 
73
- // Configuration with STUN and TURN
74
109
  const config = {
75
110
  iceServers: [
76
111
  { urls: 'stun:stun.l.google.com:19302' },
77
112
  {
78
113
  urls: 'turn:turn.example.com:3478',
79
- username: 'username',
80
- credential: 'password'
114
+ username: 'your-username',
115
+ credential: 'your-password'
81
116
  }
82
- ],
83
- encryption: false, // Optional TLS encryption
84
- transport: 'tcp' // Use TCP (or 'udp')
117
+ ]
85
118
  };
86
119
 
87
- // Create peer connection
88
- const pc = createPeerConnection(config);
120
+ const pc = new RTCPeerConnection(config);
89
121
 
90
- // Rest is the same as basic usage...
91
-
92
- channel.on('message', (event) => {
93
- console.log('Received:', event.data.toString());
94
- });
95
-
96
- // ICE candidates (includes STUN reflexive candidates)
97
122
  pc.on('icecandidate', (event) => {
98
123
  if (event.candidate) {
99
- // Send to remote peer via signaling
100
- console.log('Candidate:', event.candidate.candidate);
124
+ const candidate = event.candidate.candidate;
125
+
126
+ // Check candidate type
127
+ if (candidate.includes('typ relay')) {
128
+ console.log('TURN relay candidate:', candidate);
129
+ } else if (candidate.includes('typ srflx')) {
130
+ console.log('STUN reflexive candidate:', candidate);
131
+ } else if (candidate.includes('typ host')) {
132
+ console.log('Host candidate:', candidate);
133
+ }
101
134
  }
102
135
  });
103
136
  ```
104
137
 
105
- See [examples/with-stun-encryption.js](examples/with-stun-encryption.js) for a complete working example.
138
+ ## Configuration Options
106
139
 
107
- ## Usage
140
+ ```javascript
141
+ const config = {
142
+ // Array of ICE servers (STUN/TURN)
143
+ iceServers: [
144
+ {
145
+ urls: 'stun:stun.l.google.com:19302'
146
+ },
147
+ {
148
+ urls: [
149
+ 'turn:turn.example.com:3478?transport=udp',
150
+ 'turn:turn.example.com:3478?transport=tcp'
151
+ ],
152
+ username: 'user',
153
+ credential: 'pass'
154
+ }
155
+ ],
156
+
157
+ // ICE transport policy
158
+ iceTransportPolicy: 'all', // 'all' or 'relay'
159
+
160
+ // Bundle policy
161
+ bundlePolicy: 'balanced', // 'balanced', 'max-bundle', or 'max-compat'
162
+
163
+ // RTCP mux policy
164
+ rtcpMuxPolicy: 'require', // 'negotiate' or 'require'
165
+
166
+ // ICE candidate pool size
167
+ iceCandidatePoolSize: 0
168
+ };
169
+
170
+ const pc = new RTCPeerConnection(config);
171
+ ```
108
172
 
109
- ### Basic Example
173
+ ### Query String Parameters in Server URLs
110
174
 
111
- ```javascript
112
- const { createPeerConnection } = require('./src');
175
+ The library supports query string parameters in ICE server URLs for advanced configuration:
113
176
 
114
- // Create peer connection with STUN server
115
- const pc = createPeerConnection({
177
+ ```javascript
178
+ const config = {
116
179
  iceServers: [
117
- { urls: 'stun:stun.l.google.com:19302' }
180
+ // Transport selection
181
+ {
182
+ urls: 'turn:turn.example.com:3478?transport=udp',
183
+ username: 'user',
184
+ credential: 'pass'
185
+ },
186
+
187
+ // Multiple parameters
188
+ {
189
+ urls: 'turn:turn.example.com:3478?transport=tcp&ttl=86400',
190
+ username: 'user',
191
+ credential: 'pass'
192
+ },
193
+
194
+ // Multiple URLs with different transports
195
+ {
196
+ urls: [
197
+ 'turn:turn.cloudflare.com:3478?transport=udp',
198
+ 'turn:turn.cloudflare.com:3478?transport=tcp',
199
+ 'turns:turn.cloudflare.com:5349?transport=tcp'
200
+ ],
201
+ username: 'cloudflare_user',
202
+ credential: 'cloudflare_pass'
203
+ }
118
204
  ]
119
- });
205
+ };
206
+ ```
207
+
208
+ **Supported Query Parameters:**
209
+ - `transport=udp|tcp` - Select transport protocol (UDP or TCP)
210
+ - `ttl=<seconds>` - Set allocation lifetime for TURN (default: 600)
211
+ - Custom parameters - Can be added for vendor-specific features
212
+
213
+ **URL Format Examples:**
214
+ - `stun:host:port` - Basic STUN server
215
+ - `turn:host:port?transport=udp` - TURN with UDP transport
216
+ - `turn:host:port?transport=tcp&custom=value` - Multiple parameters
217
+ - `turns:host:port?transport=tcp` - Secure TURN over TLS
120
218
 
121
- // Create a data channel
219
+ ## Data Channel API
220
+
221
+ ```javascript
222
+ // Create data channel with options
122
223
  const channel = pc.createDataChannel('myChannel', {
123
- ordered: true
224
+ ordered: true, // Guarantee message order
225
+ maxRetransmits: 3, // Max retransmissions (if not ordered)
226
+ maxPacketLifeTime: 3000, // Max packet lifetime in ms
227
+ protocol: 'custom', // Sub-protocol
228
+ negotiated: false, // Manual negotiation
229
+ id: 0 // Channel ID (if negotiated)
124
230
  });
125
231
 
126
- // Handle channel events
232
+ // Events
127
233
  channel.on('open', () => {
128
- console.log('DataChannel opened');
129
- channel.send('Hello, peer!');
130
- });
131
-
132
- channel.on('message', (event) => {
133
- console.log('Received:', event.data);
234
+ console.log('Channel opened');
134
235
  });
135
236
 
136
237
  channel.on('close', () => {
137
- console.log('DataChannel closed');
238
+ console.log('Channel closed');
138
239
  });
139
240
 
140
- // Handle peer connection events
141
- pc.on('icecandidate', (event) => {
142
- if (event.candidate) {
143
- // Send candidate to remote peer via signaling
144
- console.log('ICE candidate:', event.candidate);
145
- }
241
+ channel.on('error', (error) => {
242
+ console.error('Channel error:', error);
146
243
  });
147
244
 
148
- pc.on('datachannel', (event) => {
149
- // Handle incoming data channel from remote peer
150
- const remoteChannel = event.channel;
151
- console.log('Remote channel opened:', remoteChannel.label);
245
+ channel.on('message', (event) => {
246
+ console.log('Message received:', event.data);
152
247
  });
153
248
 
154
- // Create and send offer
155
- pc.createOffer()
156
- .then(offer => pc.setLocalDescription(offer))
157
- .then(() => {
158
- // Send offer to remote peer via signaling
159
- console.log('Offer created:', pc.localDescription);
160
- });
249
+ // Send data
250
+ channel.send('Hello World');
251
+ channel.send(Buffer.from([1, 2, 3, 4])); // Binary data
252
+
253
+ // Close channel
254
+ channel.close();
161
255
  ```
162
256
 
163
- ### Complete Signaling Example
257
+ ## RTCPeerConnection Events
164
258
 
165
259
  ```javascript
166
- const { createPeerConnection } = require('./src');
260
+ const pc = new RTCPeerConnection(config);
167
261
 
168
- // Peer 1 (Offerer)
169
- const pc1 = createPeerConnection({
170
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
262
+ // ICE candidate discovered
263
+ pc.on('icecandidate', (event) => {
264
+ // event.candidate contains the ICE candidate
171
265
  });
172
266
 
173
- // Peer 2 (Answerer)
174
- const pc2 = createPeerConnection({
175
- iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
267
+ // ICE gathering state changed
268
+ pc.on('icegatheringstatechange', () => {
269
+ console.log('Gathering state:', pc.iceGatheringState);
270
+ // 'new', 'gathering', or 'complete'
176
271
  });
177
272
 
178
- // Exchange ICE candidates
179
- pc1.on('icecandidate', (event) => {
180
- if (event.candidate) {
181
- pc2.addIceCandidate(event.candidate);
182
- }
273
+ // ICE connection state changed
274
+ pc.on('iceconnectionstatechange', () => {
275
+ console.log('ICE state:', pc.iceConnectionState);
276
+ // 'new', 'checking', 'connected', 'completed', 'failed', 'disconnected', 'closed'
183
277
  });
184
278
 
185
- pc2.on('icecandidate', (event) => {
186
- if (event.candidate) {
187
- pc1.addIceCandidate(event.candidate);
188
- }
279
+ // Connection state changed
280
+ pc.on('connectionstatechange', () => {
281
+ console.log('Connection state:', pc.connectionState);
282
+ // 'new', 'connecting', 'connected', 'disconnected', 'failed', 'closed'
189
283
  });
190
284
 
191
- // Handle incoming data channel on peer 2
192
- pc2.on('datachannel', (event) => {
193
- const channel = event.channel;
194
- channel.on('message', (event) => {
195
- console.log('Peer 2 received:', event.data);
196
- channel.send('Hello from Peer 2!');
197
- });
285
+ // Signaling state changed
286
+ pc.on('signalingstatechange', () => {
287
+ console.log('Signaling state:', pc.signalingState);
288
+ // 'stable', 'have-local-offer', 'have-remote-offer', 'have-local-pranswer', 'have-remote-pranswer', 'closed'
198
289
  });
199
290
 
200
- // Create data channel on peer 1
201
- const channel = pc1.createDataChannel('chat');
202
-
203
- channel.on('open', () => {
204
- console.log('Channel opened');
205
- channel.send('Hello from Peer 1!');
291
+ // Data channel received (for answerer)
292
+ pc.on('datachannel', (event) => {
293
+ const channel = event.channel;
294
+ console.log('Received data channel:', channel.label);
206
295
  });
207
296
 
208
- channel.on('message', (event) => {
209
- console.log('Peer 1 received:', event.data);
297
+ // Negotiation needed
298
+ pc.on('negotiationneeded', () => {
299
+ console.log('Negotiation needed');
210
300
  });
211
-
212
- // Start signaling
213
- async function connect() {
214
- // Create offer
215
- const offer = await pc1.createOffer();
216
- await pc1.setLocalDescription(offer);
217
-
218
- // Set remote description on peer 2
219
- await pc2.setRemoteDescription(offer);
220
-
221
- // Create answer
222
- const answer = await pc2.createAnswer();
223
- await pc2.setLocalDescription(answer);
224
-
225
- // Set remote description on peer 1
226
- await pc1.setRemoteDescription(answer);
227
- }
228
-
229
- connect();
230
301
  ```
231
302
 
232
- ## API Reference
233
-
234
- ### RTCPeerConnection
303
+ ## Complete Example: Two-Peer Communication
235
304
 
236
- #### Constructor
237
305
  ```javascript
238
- new RTCPeerConnection(configuration, nativePeerConnectionFactory)
239
- ```
240
-
241
- #### Properties
242
- - `signalingState` - Current signaling state
243
- - `iceGatheringState` - Current ICE gathering state
244
- - `iceConnectionState` - Current ICE connection state
245
- - `connectionState` - Current connection state
246
- - `localDescription` - Local session description
247
- - `remoteDescription` - Remote session description
248
-
249
- #### Methods
250
- - `createOffer(options)` - Create an SDP offer
251
- - `createAnswer(options)` - Create an SDP answer
252
- - `setLocalDescription(description)` - Set local description
253
- - `setRemoteDescription(description)` - Set remote description
254
- - `addIceCandidate(candidate)` - Add an ICE candidate
255
- - `createDataChannel(label, options)` - Create a data channel
256
- - `getConfiguration()` - Get current configuration
257
- - `setConfiguration(configuration)` - Update configuration
258
- - `close()` - Close the peer connection
259
- - `getStats()` - Get connection statistics
260
-
261
- #### Events
262
- - `signalingstatechange` - Signaling state changed
263
- - `iceconnectionstatechange` - ICE connection state changed
264
- - `icegatheringstatechange` - ICE gathering state changed
265
- - `connectionstatechange` - Connection state changed
266
- - `icecandidate` - New ICE candidate available
267
- - `datachannel` - Remote data channel opened
268
- - `negotiationneeded` - Negotiation needed
269
-
270
- ### RTCDataChannel
271
-
272
- #### Properties
273
- - `label` - Channel label
274
- - `ordered` - Whether messages are ordered
275
- - `maxPacketLifeTime` - Maximum packet lifetime
276
- - `maxRetransmits` - Maximum retransmits
277
- - `protocol` - Subprotocol name
278
- - `negotiated` - Whether channel was negotiated
279
- - `id` - Channel ID
280
- - `readyState` - Current state: 'connecting', 'open', 'closing', 'closed'
281
- - `bufferedAmount` - Bytes queued to send
282
- - `bufferedAmountLowThreshold` - Threshold for bufferedamountlow event
283
- - `binaryType` - Binary data format: 'arraybuffer' or 'blob'
284
-
285
- #### Methods
286
- - `send(data)` - Send data (string, ArrayBuffer, or ArrayBufferView)
287
- - `close()` - Close the channel
306
+ const { RTCPeerConnection } = require('node-rtc-connection');
307
+
308
+ async function createPeerConnection() {
309
+ const config = {
310
+ iceServers: [
311
+ { urls: 'stun:stun.l.google.com:19302' }
312
+ ]
313
+ };
314
+
315
+ // Create peer connections
316
+ const offerer = new RTCPeerConnection(config);
317
+ const answerer = new RTCPeerConnection(config);
318
+
319
+ // Exchange ICE candidates
320
+ offerer.on('icecandidate', (e) => {
321
+ if (e.candidate) answerer.addIceCandidate(e.candidate);
322
+ });
288
323
 
289
- #### Events
290
- - `open` - Channel opened
291
- - `close` - Channel closed
292
- - `message` - Message received
293
- - `error` - Error occurred
294
- - `bufferedamountlow` - Buffered amount dropped below threshold
324
+ answerer.on('icecandidate', (e) => {
325
+ if (e.candidate) offerer.addIceCandidate(e.candidate);
326
+ });
295
327
 
296
- ## Testing
328
+ // Set up data channel on offerer
329
+ const channel = offerer.createDataChannel('chat');
297
330
 
298
- node-rtc-connection includes comprehensive unit tests covering all components:
331
+ channel.on('open', () => {
332
+ console.log('Offerer: Channel opened');
333
+ channel.send('Hello from offerer!');
334
+ });
299
335
 
300
- ```bash
301
- # Run all unit tests (fast, ~500ms)
302
- npm test
336
+ channel.on('message', (event) => {
337
+ console.log('Offerer received:', event.data);
338
+ });
303
339
 
304
- # Run tests in watch mode
305
- npm run test:watch
340
+ // Answerer receives data channel
341
+ answerer.on('datachannel', (event) => {
342
+ const channel = event.channel;
306
343
 
307
- # Run integration tests (slower, uses real networking)
308
- npm run test:integration
344
+ channel.on('open', () => {
345
+ console.log('Answerer: Channel opened');
346
+ });
309
347
 
310
- # Run all tests including integration
311
- npm run test:all
312
- ```
348
+ channel.on('message', (event) => {
349
+ console.log('Answerer received:', event.data);
350
+ channel.send('Hello from answerer!');
351
+ });
352
+ });
313
353
 
314
- **Test Coverage**: 96 unit tests with 100% pass rate. See [TEST_COVERAGE.md](TEST_COVERAGE.md) for detailed coverage information.
354
+ // Perform signaling
355
+ const offer = await offerer.createOffer();
356
+ await offerer.setLocalDescription(offer);
315
357
 
316
- ## Implementation Notes
358
+ await answerer.setRemoteDescription(offer);
359
+ const answer = await answerer.createAnswer();
360
+ await answerer.setLocalDescription(answer);
317
361
 
318
- ### Current Implementation
362
+ await offerer.setRemoteDescription(answer);
319
363
 
320
- This implementation uses **real Node.js networking** via the `net` package for peer-to-peer TCP connections:
364
+ // Wait for connection
365
+ await new Promise(resolve => setTimeout(resolve, 2000));
321
366
 
322
- - **Real TCP connections** between peers
323
- - ✅ **Actual data transmission** over sockets
324
- - ✅ **Real SDP generation** with network addresses
325
- - ✅ **Working ICE candidates** with local IP addresses
326
- - ✅ **Bidirectional messaging** between data channels
327
- - ✅ **Connection lifecycle** management
367
+ // Clean up
368
+ channel.close();
369
+ offerer.close();
370
+ answerer.close();
371
+ }
328
372
 
329
- The `NativePeerConnectionFactory` creates TCP servers and clients to establish peer-to-peer connections. Data channels transmit messages over these TCP connections using a simple framing protocol.
373
+ createPeerConnection().catch(console.error);
374
+ ```
330
375
 
331
- ### How It Works
376
+ ## Example Files
332
377
 
333
- 1. **Offer/Answer Exchange**: Peers exchange SDP containing their IP address and port
334
- 2. **TCP Server**: Each peer creates a TCP server listening on a random port
335
- 3. **Connection**: The answerer connects to the offerer's TCP server
336
- 4. **Data Channel Protocol**: Messages are framed with length + channel label + data
337
- 5. **Bidirectional Communication**: Both peers can send and receive on the established socket
378
+ The package includes several example files demonstrating different features:
338
379
 
339
- ### Example Output
380
+ - **`examples/real-networking-demo.js`** - Basic peer-to-peer connection without STUN/TURN
381
+ - **`examples/stun-demo.js`** - STUN server usage for NAT traversal
382
+ - **`examples/turn-demo.js`** - TURN relay with full peer-to-peer communication
383
+ - **`examples/peer-connection-demo.js`** - Simple peer connection setup
384
+ - **`examples/simple-datachannel.js`** - Basic data channel usage
340
385
 
386
+ Run examples:
341
387
  ```bash
342
- $ node examples/real-networking.js
343
-
344
- PC1: Data channel opened!
345
- ✓ PC2: Data channel opened!
346
-
347
- PC1: Sending first message...
348
- 📨 PC2 received: Hello from Peer 1!
349
- PC2: Sending reply...
350
- 📨 PC1 received: Hello from Peer 2! Nice to meet you.
388
+ node examples/real-networking-demo.js
389
+ node examples/stun-demo.js
390
+ node examples/turn-demo.js
351
391
  ```
352
392
 
353
- ## Development & Contributing
393
+ ## Configuration File
354
394
 
355
- ### Setup
395
+ The examples use a `peer.config.json` file for centralized configuration:
356
396
 
357
- ```bash
358
- git clone https://github.com/nmhung1210/nodertc.git
359
- cd nodertc
360
- npm install
397
+ ```json
398
+ {
399
+ "iceServers": [
400
+ { "urls": "stun:stun.l.google.com:19302" }
401
+ ],
402
+ "localDemo": {
403
+ "iceServers": []
404
+ },
405
+ "stunOnly": {
406
+ "iceServers": [
407
+ { "urls": "stun:stun.l.google.com:19302" }
408
+ ]
409
+ },
410
+ "turnConfig": {
411
+ "iceServers": [
412
+ { "urls": "stun:stun.example.com:3478" },
413
+ {
414
+ "urls": "turn:turn.example.com:3478",
415
+ "username": "user",
416
+ "credential": "pass"
417
+ }
418
+ ]
419
+ }
420
+ }
361
421
  ```
362
422
 
363
- ### Testing
423
+ ## API Reference
364
424
 
365
- ```bash
366
- # Run all tests
367
- npm test
425
+ ### RTCPeerConnection
368
426
 
369
- # Run specific test suites
370
- npm run test:stun # STUN tests
371
- npm run test:turn # TURN tests
372
- npm run test:integration # Integration tests
427
+ #### Constructor
428
+ ```javascript
429
+ new RTCPeerConnection(configuration?)
373
430
  ```
374
431
 
375
- ### Building
376
-
377
- ```bash
378
- npm run build
379
- ```
432
+ #### Methods
433
+ - `createOffer(options?)` - Create SDP offer
434
+ - `createAnswer(options?)` - Create SDP answer
435
+ - `setLocalDescription(description)` - Set local SDP
436
+ - `setRemoteDescription(description)` - Set remote SDP
437
+ - `addIceCandidate(candidate)` - Add remote ICE candidate
438
+ - `createDataChannel(label, options?)` - Create data channel
439
+ - `close()` - Close the connection
380
440
 
381
- This creates CommonJS and ES Module bundles in `dist/`.
441
+ #### Properties
442
+ - `localDescription` - Local SDP description
443
+ - `remoteDescription` - Remote SDP description
444
+ - `signalingState` - Current signaling state
445
+ - `iceGatheringState` - ICE gathering state
446
+ - `iceConnectionState` - ICE connection state
447
+ - `connectionState` - Overall connection state
382
448
 
383
- ### CI/CD
449
+ ### RTCDataChannel
384
450
 
385
- This project uses GitHub Actions for automated testing and publishing:
451
+ #### Methods
452
+ - `send(data)` - Send data (string or Buffer)
453
+ - `close()` - Close the channel
386
454
 
387
- - **Test Workflow**: Runs on push/PR, tests on Node.js 18.x, 20.x, 22.x
388
- - **Publish Workflow**: Triggers on version tags, automatically publishes to NPM
455
+ #### Properties
456
+ - `label` - Channel label
457
+ - `ordered` - Whether messages are ordered
458
+ - `maxRetransmits` - Maximum retransmissions
459
+ - `maxPacketLifeTime` - Maximum packet lifetime
460
+ - `protocol` - Sub-protocol
461
+ - `negotiated` - Whether manually negotiated
462
+ - `id` - Channel ID
463
+ - `readyState` - Current state ('connecting', 'open', 'closing', 'closed')
464
+ - `bufferedAmount` - Bytes queued to send
389
465
 
390
- See [CONTRIBUTING.md](CONTRIBUTING.md) for detailed publishing instructions.
466
+ ## Requirements
391
467
 
392
- ## Differences from Browser WebRTC
468
+ - Node.js 14 or higher
469
+ - UDP/TCP network access for ICE connectivity
393
470
 
394
- ### Not Included (DataChannel-only focus)
395
- - ❌ MediaStream / MediaStreamTrack
396
- - ❌ getUserMedia
397
- - ❌ RTCRtpSender / RTCRtpReceiver
398
- - ❌ RTCRtpTransceiver
399
- - ❌ Audio/Video codecs
400
- - ❌ RTCDTMFSender
401
- - ❌ Media constraints
471
+ ## Setting Up Your Own TURN Server
402
472
 
403
- ### Simplified
404
- - Event handling uses Node.js EventEmitter instead of DOM events
405
- - No dependency on browser APIs
406
- - Synchronous where possible (async only for native operations)
473
+ For production use, it's recommended to run your own TURN server using [coturn](https://github.com/coturn/coturn):
407
474
 
408
- ## Contributing
475
+ ```bash
476
+ # Install coturn
477
+ apt-get install coturn
409
478
 
410
- Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
479
+ # Basic configuration
480
+ turnserver -v -L 0.0.0.0 -a -u user:password -r realm
481
+ ```
411
482
 
412
483
  ## License
413
484
 
414
- MIT License - see [LICENSE](LICENSE) file for details.
485
+ BSD-3-Clause
415
486
 
416
- ## Credits
487
+ ## Contributing
417
488
 
418
- Ported from Chromium's WebRTC implementation:
419
- - Original source: `third_party/blink/renderer/modules/peerconnection/`
420
- - Copyright (C) 2012 Google Inc.
489
+ Contributions are welcome! Please feel free to submit issues or pull requests.
421
490
 
422
- ## Links
491
+ ## Acknowledgments
423
492
 
424
- - [NPM Package](https://www.npmjs.com/package/node-rtc-connection)
425
- - [GitHub Repository](https://github.com/nmhung1210/nodertc)
426
- - [Issues](https://github.com/nmhung1210/nodertc/issues)
427
- - [Contributing Guide](CONTRIBUTING.md)
493
+ This implementation is inspired by and follows the WebRTC standards and specifications, with particular reference to Chromium's WebRTC implementation.