node-rtc-connection 1.0.5 → 1.0.6
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/dist/index.cjs +125 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +125 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/NativePeerConnectionFactory.js +125 -17
package/dist/index.cjs
CHANGED
|
@@ -2400,6 +2400,9 @@ function requireNativePeerConnectionFactory () {
|
|
|
2400
2400
|
this._secureConnection = null;
|
|
2401
2401
|
this._udpTransport = null;
|
|
2402
2402
|
this._iceCandidates = [];
|
|
2403
|
+
this._remoteCandidates = [];
|
|
2404
|
+
this._selectedLocalCandidate = null;
|
|
2405
|
+
this._selectedRemoteCandidate = null;
|
|
2403
2406
|
|
|
2404
2407
|
console.log('[NativePeerConnection] Created with STUN/ICE/Encryption support');
|
|
2405
2408
|
console.log(` - Encryption: ${this._useEncryption ? 'enabled' : 'disabled (requires valid certs)'}`);
|
|
@@ -2545,22 +2548,106 @@ function requireNativePeerConnectionFactory () {
|
|
|
2545
2548
|
}
|
|
2546
2549
|
|
|
2547
2550
|
if (!candidate || !candidate.candidate) {
|
|
2551
|
+
// null candidate signals end of candidates - try to select best pair
|
|
2552
|
+
if (this._remoteCandidates.length > 0 && !this._selectedRemoteCandidate) {
|
|
2553
|
+
this._selectBestCandidatePair();
|
|
2554
|
+
}
|
|
2555
|
+
return;
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
// Parse ICE candidate
|
|
2559
|
+
const parsed = this._parseIceCandidate(candidate.candidate);
|
|
2560
|
+
if (!parsed) {
|
|
2548
2561
|
return;
|
|
2549
2562
|
}
|
|
2550
2563
|
|
|
2551
|
-
//
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2564
|
+
// Store the remote candidate
|
|
2565
|
+
this._remoteCandidates.push(parsed);
|
|
2566
|
+
console.log(`[NativePeerConnection] Added remote ICE candidate (${parsed.type}): ${parsed.ip}:${parsed.port}`);
|
|
2567
|
+
|
|
2568
|
+
// For backward compatibility, set remote address immediately if not set
|
|
2569
|
+
if (!this._remoteAddress) {
|
|
2570
|
+
this._remoteAddress = parsed.ip;
|
|
2571
|
+
this._remotePort = parsed.port;
|
|
2556
2572
|
console.log(`[NativePeerConnection] Remote address: ${this._remoteAddress}:${this._remotePort}`);
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
// If we haven't selected a pair yet, try to select now
|
|
2576
|
+
if (!this._selectedRemoteCandidate && this._iceCandidates.length > 0) {
|
|
2577
|
+
this._selectBestCandidatePair();
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
// If we selected a pair and are offerer, connect
|
|
2581
|
+
if (this._selectedRemoteCandidate && this._isOfferer &&
|
|
2582
|
+
this._signalingState === 0 && !this._socket) {
|
|
2583
|
+
await this._connectToPeer();
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
/**
|
|
2588
|
+
* Parse ICE candidate string
|
|
2589
|
+
* @private
|
|
2590
|
+
*/
|
|
2591
|
+
_parseIceCandidate(candidateStr) {
|
|
2592
|
+
const parts = candidateStr.split(' ');
|
|
2593
|
+
if (parts.length < 6) {
|
|
2594
|
+
return null;
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
return {
|
|
2598
|
+
foundation: parts[0].replace('candidate:', ''),
|
|
2599
|
+
component: parts[1],
|
|
2600
|
+
protocol: parts[2],
|
|
2601
|
+
priority: parseInt(parts[3], 10),
|
|
2602
|
+
ip: parts[4],
|
|
2603
|
+
port: parseInt(parts[5], 10),
|
|
2604
|
+
type: parts[7], // typ host/srflx/relay
|
|
2605
|
+
relatedAddress: parts[9] || null,
|
|
2606
|
+
relatedPort: parts[11] ? parseInt(parts[11], 10) : null
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
/**
|
|
2611
|
+
* Select best candidate pair for connection
|
|
2612
|
+
* Prioritizes: relay > srflx > host
|
|
2613
|
+
* @private
|
|
2614
|
+
*/
|
|
2615
|
+
_selectBestCandidatePair() {
|
|
2616
|
+
if (this._remoteCandidates.length === 0 || this._iceCandidates.length === 0) {
|
|
2617
|
+
return;
|
|
2618
|
+
}
|
|
2619
|
+
|
|
2620
|
+
// Priority order: relay > srflx > host
|
|
2621
|
+
const typePriority = { 'relay': 3, 'srflx': 2, 'host': 1 };
|
|
2622
|
+
|
|
2623
|
+
// Find best local candidate
|
|
2624
|
+
let bestLocal = this._iceCandidates[0];
|
|
2625
|
+
for (const candidate of this._iceCandidates) {
|
|
2626
|
+
if (typePriority[candidate.type] > typePriority[bestLocal.type]) {
|
|
2627
|
+
bestLocal = candidate;
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2631
|
+
// Find best remote candidate
|
|
2632
|
+
let bestRemote = this._remoteCandidates[0];
|
|
2633
|
+
for (const candidate of this._remoteCandidates) {
|
|
2634
|
+
if (typePriority[candidate.type] > typePriority[bestRemote.type]) {
|
|
2635
|
+
bestRemote = candidate;
|
|
2562
2636
|
}
|
|
2563
2637
|
}
|
|
2638
|
+
|
|
2639
|
+
this._selectedLocalCandidate = bestLocal;
|
|
2640
|
+
this._selectedRemoteCandidate = bestRemote;
|
|
2641
|
+
|
|
2642
|
+
// Update addresses for connection
|
|
2643
|
+
this._localAddress = bestLocal.ip;
|
|
2644
|
+
this._localPort = bestLocal.port;
|
|
2645
|
+
this._remoteAddress = bestRemote.ip;
|
|
2646
|
+
this._remotePort = bestRemote.port;
|
|
2647
|
+
|
|
2648
|
+
console.log(`[NativePeerConnection] Selected candidate pair:`);
|
|
2649
|
+
console.log(` Local: ${bestLocal.type} ${this._localAddress}:${this._localPort}`);
|
|
2650
|
+
console.log(` Remote: ${bestRemote.type} ${this._remoteAddress}:${this._remotePort}`);
|
|
2564
2651
|
}
|
|
2565
2652
|
|
|
2566
2653
|
/**
|
|
@@ -2696,14 +2783,24 @@ function requireNativePeerConnectionFactory () {
|
|
|
2696
2783
|
return;
|
|
2697
2784
|
}
|
|
2698
2785
|
|
|
2699
|
-
//
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2786
|
+
// Check if we're using relay candidates - if so, skip tie-breaking
|
|
2787
|
+
const usingRelay = this._selectedLocalCandidate?.type === 'relay' ||
|
|
2788
|
+
this._selectedRemoteCandidate?.type === 'relay';
|
|
2789
|
+
|
|
2790
|
+
if (!usingRelay) {
|
|
2791
|
+
// Tie-breaking: only connect if our port is higher than remote port
|
|
2792
|
+
// This ensures only one peer connects, avoiding the race condition
|
|
2793
|
+
// Note: This only works for direct connections (host/srflx)
|
|
2794
|
+
if (this._localPort < this._remotePort) {
|
|
2795
|
+
console.log(`[NativePeerConnection] Not connecting (local port ${this._localPort} < remote port ${this._remotePort}), waiting for incoming`);
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2704
2798
|
}
|
|
2705
2799
|
|
|
2706
2800
|
console.log(`[NativePeerConnection] Connecting to ${this._remoteAddress}:${this._remotePort}`);
|
|
2801
|
+
if (usingRelay) {
|
|
2802
|
+
console.log(`[NativePeerConnection] Using TURN relay connection`);
|
|
2803
|
+
}
|
|
2707
2804
|
|
|
2708
2805
|
this._socket = new net.Socket();
|
|
2709
2806
|
|
|
@@ -2996,7 +3093,12 @@ a=max-message-size:262144
|
|
|
2996
3093
|
|
|
2997
3094
|
// Emit each candidate
|
|
2998
3095
|
for (const candidate of candidates) {
|
|
2999
|
-
|
|
3096
|
+
// Parse and store the candidate
|
|
3097
|
+
const parsed = this._parseIceCandidate(candidate.candidate);
|
|
3098
|
+
if (parsed) {
|
|
3099
|
+
this._iceCandidates.push(parsed);
|
|
3100
|
+
}
|
|
3101
|
+
|
|
3000
3102
|
this.emit('icecandidate', {
|
|
3001
3103
|
candidate: candidate.candidate,
|
|
3002
3104
|
sdpMid: candidate.sdpMid,
|
|
@@ -3010,8 +3112,14 @@ a=max-message-size:262144
|
|
|
3010
3112
|
|
|
3011
3113
|
// Fallback: emit only local host candidate
|
|
3012
3114
|
if (this._localAddress && this._localPort) {
|
|
3115
|
+
const candidateStr = `candidate:1 1 tcp 2130706431 ${this._localAddress} ${this._localPort} typ host`;
|
|
3116
|
+
const parsed = this._parseIceCandidate(candidateStr);
|
|
3117
|
+
if (parsed) {
|
|
3118
|
+
this._iceCandidates.push(parsed);
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3013
3121
|
const candidate = {
|
|
3014
|
-
candidate:
|
|
3122
|
+
candidate: candidateStr,
|
|
3015
3123
|
sdpMid: 'data',
|
|
3016
3124
|
sdpMLineIndex: 0
|
|
3017
3125
|
};
|