werift 0.24.4 → 0.25.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.
- package/README.md +116 -113
- package/lib/common/src/transport.d.ts +22 -2
- package/lib/common/src/transport.js +84 -26
- package/lib/common/src/transport.js.map +1 -1
- package/lib/ice/src/exceptions.d.ts +9 -0
- package/lib/ice/src/exceptions.js +23 -1
- package/lib/ice/src/exceptions.js.map +1 -1
- package/lib/ice/src/ice.d.ts +40 -0
- package/lib/ice/src/ice.js +194 -28
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +26 -0
- package/lib/ice/src/iceBase.js.map +1 -1
- package/lib/ice/src/stun/const.d.ts +7 -0
- package/lib/ice/src/stun/const.js +8 -0
- package/lib/ice/src/stun/const.js.map +1 -1
- package/lib/ice/src/stun/protocol.js +1 -4
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/tcpProtocol.d.ts +7 -1
- package/lib/ice/src/stun/tcpProtocol.js +65 -14
- package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.d.ts +12 -1
- package/lib/ice/src/stun/transaction.js +37 -4
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +40 -15
- package/lib/ice/src/turn/protocol.js +141 -32
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +8 -0
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/index.mjs +6175 -4073
- package/lib/nonstandard/index.mjs +286 -1003
- package/lib/polyfill/dom.mjs +23794 -0
- package/lib/polyfill/index.mjs +23794 -0
- package/lib/rtp/src/extra/container/mp4/container.js +12 -4
- package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4.js +8 -3
- package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js +3 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
- package/lib/sctp/src/chunk.d.ts +5 -0
- package/lib/sctp/src/chunk.js +16 -11
- package/lib/sctp/src/chunk.js.map +1 -1
- package/lib/sctp/src/index.d.ts +3 -1
- package/lib/sctp/src/index.js +10 -1
- package/lib/sctp/src/index.js.map +1 -1
- package/lib/sctp/src/sctp.d.ts +12 -3
- package/lib/sctp/src/sctp.js +51 -18
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/const.js +2 -0
- package/lib/webrtc/src/const.js.map +1 -1
- package/lib/webrtc/src/errors.d.ts +9 -1
- package/lib/webrtc/src/errors.js +19 -0
- package/lib/webrtc/src/errors.js.map +1 -1
- package/lib/webrtc/src/media/codec.d.ts +5 -0
- package/lib/webrtc/src/media/codec.js +21 -0
- package/lib/webrtc/src/media/codec.js.map +1 -1
- package/lib/webrtc/src/media/codecCompatibility.d.ts +23 -0
- package/lib/webrtc/src/media/codecCompatibility.js +138 -0
- package/lib/webrtc/src/media/codecCompatibility.js.map +1 -0
- package/lib/webrtc/src/media/index.d.ts +1 -0
- package/lib/webrtc/src/media/index.js +1 -0
- package/lib/webrtc/src/media/index.js.map +1 -1
- package/lib/webrtc/src/media/router.d.ts +2 -0
- package/lib/webrtc/src/media/router.js +23 -3
- package/lib/webrtc/src/media/router.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +12 -0
- package/lib/webrtc/src/media/rtpReceiver.js +35 -0
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.d.ts +65 -4
- package/lib/webrtc/src/media/rtpSender.js +264 -35
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/media/rtpTransceiver.d.ts +42 -0
- package/lib/webrtc/src/media/rtpTransceiver.js +157 -4
- package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
- package/lib/webrtc/src/media/track.d.ts +29 -1
- package/lib/webrtc/src/media/track.js +164 -5
- package/lib/webrtc/src/media/track.js.map +1 -1
- package/lib/webrtc/src/nonstandard/index.d.ts +0 -1
- package/lib/webrtc/src/nonstandard/index.js +0 -1
- package/lib/webrtc/src/nonstandard/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +2 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
- package/lib/webrtc/src/nonstandard/userMedia.d.ts +1 -2
- package/lib/webrtc/src/nonstandard/userMedia.js +30 -14
- package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +126 -5
- package/lib/webrtc/src/peerConnection.js +609 -136
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/polyfill/api.d.ts +14 -0
- package/lib/webrtc/src/polyfill/api.js +23 -0
- package/lib/webrtc/src/polyfill/api.js.map +1 -0
- package/lib/webrtc/src/polyfill/browserIdentity.d.ts +11 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js +59 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js.map +1 -0
- package/lib/webrtc/src/polyfill/dom.d.ts +11 -0
- package/lib/webrtc/src/polyfill/dom.js +18 -0
- package/lib/webrtc/src/polyfill/dom.js.map +1 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.d.ts +2 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js +22 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/globals.d.ts +28 -0
- package/lib/webrtc/src/polyfill/globals.js +3 -0
- package/lib/webrtc/src/polyfill/globals.js.map +1 -0
- package/lib/webrtc/src/polyfill/index.d.ts +2 -0
- package/lib/webrtc/src/polyfill/index.js +19 -0
- package/lib/webrtc/src/polyfill/index.js.map +1 -0
- package/lib/webrtc/src/polyfill/install.d.ts +13 -0
- package/lib/webrtc/src/polyfill/install.js +266 -0
- package/lib/webrtc/src/polyfill/install.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaDevices.d.ts +38 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js +228 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaRegister.d.ts +51 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js +14 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js.map +1 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.d.ts +3 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js +52 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/callback.d.ts +16 -0
- package/lib/webrtc/src/polyfill/registers/callback.js +57 -0
- package/lib/webrtc/src/polyfill/registers/callback.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/empty.d.ts +2 -0
- package/lib/webrtc/src/polyfill/registers/empty.js +28 -0
- package/lib/webrtc/src/polyfill/registers/empty.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.d.ts +36 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js +242 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.d.ts +17 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js +143 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.d.ts +18 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js +36 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtpCodec.d.ts +17 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js +93 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js.map +1 -0
- package/lib/webrtc/src/polyfill/selectSettings.d.ts +31 -0
- package/lib/webrtc/src/polyfill/selectSettings.js +156 -0
- package/lib/webrtc/src/polyfill/selectSettings.js.map +1 -0
- package/lib/webrtc/src/polyfill/sourceIo.d.ts +21 -0
- package/lib/webrtc/src/polyfill/sourceIo.js +298 -0
- package/lib/webrtc/src/polyfill/sourceIo.js.map +1 -0
- package/lib/webrtc/src/polyfill/trackStop.d.ts +4 -0
- package/lib/webrtc/src/polyfill/trackStop.js +16 -0
- package/lib/webrtc/src/polyfill/trackStop.js.map +1 -0
- package/lib/webrtc/src/sctpManager.d.ts +2 -1
- package/lib/webrtc/src/sctpManager.js +5 -2
- package/lib/webrtc/src/sctpManager.js.map +1 -1
- package/lib/webrtc/src/sdp.d.ts +1 -1
- package/lib/webrtc/src/sdp.js +5 -6
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/sdpManager.d.ts +38 -1
- package/lib/webrtc/src/sdpManager.js +236 -30
- package/lib/webrtc/src/sdpManager.js.map +1 -1
- package/lib/webrtc/src/secureTransportManager.d.ts +43 -12
- package/lib/webrtc/src/secureTransportManager.js +123 -47
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transceiverManager.d.ts +91 -6
- package/lib/webrtc/src/transceiverManager.js +477 -62
- package/lib/webrtc/src/transceiverManager.js.map +1 -1
- package/lib/webrtc/src/transport/ice.d.ts +8 -0
- package/lib/webrtc/src/transport/ice.js +17 -1
- package/lib/webrtc/src/transport/ice.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.d.ts +3 -2
- package/lib/webrtc/src/transport/sctp.js +8 -2
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/package.json +13 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TransactionTimeout = exports.TransactionFailed = exports.TransactionError = void 0;
|
|
3
|
+
exports.AddressFamilyMismatch = exports.TransactionTimeout = exports.TransactionFailed = exports.TransactionError = void 0;
|
|
4
4
|
class TransactionError extends Error {
|
|
5
5
|
constructor() {
|
|
6
6
|
super(...arguments);
|
|
@@ -52,4 +52,26 @@ class TransactionTimeout extends TransactionError {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
exports.TransactionTimeout = TransactionTimeout;
|
|
55
|
+
/**
|
|
56
|
+
* The request target is an IP literal of a different family than the socket
|
|
57
|
+
* that would carry it, so it can never be delivered.
|
|
58
|
+
*/
|
|
59
|
+
class AddressFamilyMismatch extends Error {
|
|
60
|
+
constructor(addr, socketFamily) {
|
|
61
|
+
super(`cannot reach ${addr[0]}:${addr[1]} from an IPv${socketFamily} socket`);
|
|
62
|
+
Object.defineProperty(this, "addr", {
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true,
|
|
65
|
+
writable: true,
|
|
66
|
+
value: addr
|
|
67
|
+
});
|
|
68
|
+
Object.defineProperty(this, "socketFamily", {
|
|
69
|
+
enumerable: true,
|
|
70
|
+
configurable: true,
|
|
71
|
+
writable: true,
|
|
72
|
+
value: socketFamily
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.AddressFamilyMismatch = AddressFamilyMismatch;
|
|
55
77
|
//# sourceMappingURL=exceptions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../../../ice/src/exceptions.ts"],"names":[],"mappings":";;;AAGA,MAAa,gBAAiB,SAAQ,KAAK;IAA3C;;QACE;;;;;WAAmB;QACnB;;;;;WAAe;IACjB,CAAC;CAAA;AAHD,4CAGC;AAED,MAAa,iBAAkB,SAAQ,gBAAgB;IACrD,YACS,QAAiB,EACjB,IAAa;QAEpB,KAAK,EAAE,CAAC;QAHR;;;;mBAAO,QAAQ;WAAS;QACxB;;;;mBAAO,IAAI;WAAS;IAGtB,CAAC;IAED,IAAI,GAAG;QACL,IAAI,GAAG,GAAG,yBAAyB,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAChE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;YAC9B,GAAG,IAAI,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC;QAC/B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAjBD,8CAiBC;AAED,MAAa,kBAAmB,SAAQ,gBAAgB;IACtD,IAAI,GAAG;QACL,OAAO,4BAA4B,CAAC;IACtC,CAAC;CACF;AAJD,gDAIC","sourcesContent":["import type { Address } from \"./imports/common\";\nimport type { Message } from \"./stun/message\";\n\nexport class TransactionError extends Error {\n response?: Message;\n addr?: Address;\n}\n\nexport class TransactionFailed extends TransactionError {\n constructor(\n public response: Message,\n public addr: Address,\n ) {\n super();\n }\n\n get str() {\n let out = \"STUN transaction failed\";\n const attribute = this.response.getAttributeValue(\"ERROR-CODE\");\n if (attribute) {\n const [code, msg] = attribute;\n out += ` (${code} - ${msg})`;\n }\n return out;\n }\n}\n\nexport class TransactionTimeout extends TransactionError {\n get str() {\n return \"STUN transaction timed out\";\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"exceptions.js","sourceRoot":"","sources":["../../../../ice/src/exceptions.ts"],"names":[],"mappings":";;;AAGA,MAAa,gBAAiB,SAAQ,KAAK;IAA3C;;QACE;;;;;WAAmB;QACnB;;;;;WAAe;IACjB,CAAC;CAAA;AAHD,4CAGC;AAED,MAAa,iBAAkB,SAAQ,gBAAgB;IACrD,YACS,QAAiB,EACjB,IAAa;QAEpB,KAAK,EAAE,CAAC;QAHR;;;;mBAAO,QAAQ;WAAS;QACxB;;;;mBAAO,IAAI;WAAS;IAGtB,CAAC;IAED,IAAI,GAAG;QACL,IAAI,GAAG,GAAG,yBAAyB,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC;QAChE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;YAC9B,GAAG,IAAI,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC;QAC/B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAjBD,8CAiBC;AAED,MAAa,kBAAmB,SAAQ,gBAAgB;IACtD,IAAI,GAAG;QACL,OAAO,4BAA4B,CAAC;IACtC,CAAC;CACF;AAJD,gDAIC;AAED;;;GAGG;AACH,MAAa,qBAAsB,SAAQ,KAAK;IAC9C,YACS,IAAa,EACb,YAAmB;QAE1B,KAAK,CACH,gBAAgB,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,eAAe,YAAY,SAAS,CACvE,CAAC;QALF;;;;mBAAO,IAAI;WAAS;QACpB;;;;mBAAO,YAAY;WAAO;IAK5B,CAAC;CACF;AATD,sDASC","sourcesContent":["import type { Address } from \"./imports/common\";\nimport type { Message } from \"./stun/message\";\n\nexport class TransactionError extends Error {\n response?: Message;\n addr?: Address;\n}\n\nexport class TransactionFailed extends TransactionError {\n constructor(\n public response: Message,\n public addr: Address,\n ) {\n super();\n }\n\n get str() {\n let out = \"STUN transaction failed\";\n const attribute = this.response.getAttributeValue(\"ERROR-CODE\");\n if (attribute) {\n const [code, msg] = attribute;\n out += ` (${code} - ${msg})`;\n }\n return out;\n }\n}\n\nexport class TransactionTimeout extends TransactionError {\n get str() {\n return \"STUN transaction timed out\";\n }\n}\n\n/**\n * The request target is an IP literal of a different family than the socket\n * that would carry it, so it can never be delivered.\n */\nexport class AddressFamilyMismatch extends Error {\n constructor(\n public addr: Address,\n public socketFamily: 4 | 6,\n ) {\n super(\n `cannot reach ${addr[0]}:${addr[1]} from an IPv${socketFamily} socket`,\n );\n }\n}\n"]}
|
package/lib/ice/src/ice.d.ts
CHANGED
|
@@ -45,6 +45,22 @@ export declare class Connection implements IceConnection {
|
|
|
45
45
|
readonly stateChanged: Event<[IceState]>;
|
|
46
46
|
readonly onIceCandidate: Event<[Candidate]>;
|
|
47
47
|
constructor(_iceControlling: boolean, options?: Partial<IceOptions>);
|
|
48
|
+
/**
|
|
49
|
+
* Replace STUN/TURN servers after construction.
|
|
50
|
+
* Server-related fields are replaced (not partial-merged) so that removing
|
|
51
|
+
* TURN clears residual credentials. W3C setConfiguration replaces the ICE
|
|
52
|
+
* server list rather than merging additively.
|
|
53
|
+
*
|
|
54
|
+
* Used when servers are learned after the gatherer was built (e.g. WHIP
|
|
55
|
+
* Link headers) and must take effect before the next gather pass.
|
|
56
|
+
*/
|
|
57
|
+
setIceServers(options: Partial<IceOptions>): void;
|
|
58
|
+
/**
|
|
59
|
+
* Derive Connection.stunServer / turnServer from this.options.
|
|
60
|
+
* Shared by the constructor and setIceServers so both paths validate and
|
|
61
|
+
* default identically.
|
|
62
|
+
*/
|
|
63
|
+
private applyStunTurnServersFromOptions;
|
|
48
64
|
get iceControlling(): boolean;
|
|
49
65
|
set iceControlling(value: boolean);
|
|
50
66
|
get iceLite(): boolean;
|
|
@@ -58,6 +74,12 @@ export declare class Connection implements IceConnection {
|
|
|
58
74
|
gatherCandidates(): Promise<void>;
|
|
59
75
|
private appendLocalCandidate;
|
|
60
76
|
private ensureProtocol;
|
|
77
|
+
/**
|
|
78
|
+
* RFC 6544: the selected TCP connection is the only path for this component;
|
|
79
|
+
* once it is closed no application data or consent check can reach the peer,
|
|
80
|
+
* so fail the same way as a consent expiry instead of waiting for it.
|
|
81
|
+
*/
|
|
82
|
+
private handleConnectionClosed;
|
|
61
83
|
private getCandidatePromises;
|
|
62
84
|
connect(): Promise<void>;
|
|
63
85
|
private unfreezeInitial;
|
|
@@ -94,6 +116,24 @@ export declare class Connection implements IceConnection {
|
|
|
94
116
|
resolve: (value: void | PromiseLike<void>) => void;
|
|
95
117
|
reject: (reason?: any) => void;
|
|
96
118
|
};
|
|
119
|
+
private isTcpPair;
|
|
120
|
+
/**
|
|
121
|
+
* Aggressive nomination lets each side settle on whichever TCP connection
|
|
122
|
+
* finished first; the two sides can then pick different connections and
|
|
123
|
+
* pruning destroys the peer's choice. For TCP the controlling agent instead
|
|
124
|
+
* nominates exactly one valid pair (RFC 8445 §8.1.1 regular nomination).
|
|
125
|
+
*/
|
|
126
|
+
private usesTcpRegularNomination;
|
|
127
|
+
private checkRequestOptions;
|
|
128
|
+
/**
|
|
129
|
+
* Controlling side: nominate the highest-priority TCP pair once every
|
|
130
|
+
* higher-priority TCP pair has finished its check, so the choice does not
|
|
131
|
+
* depend on which connection happened to complete first.
|
|
132
|
+
*/
|
|
133
|
+
private nominateTcpPairIfReady;
|
|
134
|
+
private nominateTcpPair;
|
|
135
|
+
/** The agent was closed or restarted while the nomination was in flight. */
|
|
136
|
+
private isStaleNomination;
|
|
97
137
|
private addPair;
|
|
98
138
|
checkIncoming(message: Message, addr: Address, protocol: Protocol): void;
|
|
99
139
|
private tryPair;
|
package/lib/ice/src/ice.js
CHANGED
|
@@ -49,6 +49,8 @@ const tcpProtocol_1 = require("./stun/tcpProtocol");
|
|
|
49
49
|
const protocol_2 = require("./turn/protocol");
|
|
50
50
|
const utils_1 = require("./utils");
|
|
51
51
|
const log = (0, common_1.debug)("werift-ice : packages/ice/src/ice.ts : log");
|
|
52
|
+
/** Fallback STUN server when none is configured (constructor / setIceServers). */
|
|
53
|
+
const DEFAULT_STUN_SERVER = ["stun.l.google.com", 19302];
|
|
52
54
|
class Connection {
|
|
53
55
|
constructor(_iceControlling, options) {
|
|
54
56
|
Object.defineProperty(this, "_iceControlling", {
|
|
@@ -463,7 +465,8 @@ class Connection {
|
|
|
463
465
|
const result = {};
|
|
464
466
|
const { remotePassword, remoteUsername, generation } = this;
|
|
465
467
|
const localUsername = pair.localCandidate.ufrag ?? this.localUsername;
|
|
466
|
-
|
|
468
|
+
// TCP pairs use regular nomination (see nominateTcpPairIfReady).
|
|
469
|
+
const nominate = this.iceControlling && !this.remoteIsLite && !this.isTcpPair(pair);
|
|
467
470
|
const request = this.buildRequest({
|
|
468
471
|
nominate,
|
|
469
472
|
localUsername,
|
|
@@ -475,11 +478,7 @@ class Connection {
|
|
|
475
478
|
const startTime = performance.now();
|
|
476
479
|
try {
|
|
477
480
|
pair.requestsSent++;
|
|
478
|
-
const [response, addr] = await pair.protocol.request(request, pair.remoteAddr, Buffer.from(remotePassword, "utf8"),
|
|
479
|
-
if (attempt > 0) {
|
|
480
|
-
pair.retransmissionsSent++;
|
|
481
|
-
}
|
|
482
|
-
});
|
|
481
|
+
const [response, addr] = await pair.protocol.request(request, pair.remoteAddr, Buffer.from(remotePassword, "utf8"), this.checkRequestOptions(pair));
|
|
483
482
|
pair.responsesReceived++;
|
|
484
483
|
// Calculate RTT
|
|
485
484
|
const endTime = performance.now();
|
|
@@ -546,6 +545,9 @@ class Connection {
|
|
|
546
545
|
// # nominated by agressive nomination or the remote party
|
|
547
546
|
pair.nominated = true;
|
|
548
547
|
}
|
|
548
|
+
else if (this.usesTcpRegularNomination(pair)) {
|
|
549
|
+
// # nominated later by nominateTcpPairIfReady (from checkComplete)
|
|
550
|
+
}
|
|
549
551
|
else if (this.iceControlling && !this.nominating) {
|
|
550
552
|
// # perform regular nomination
|
|
551
553
|
this.nominating = true;
|
|
@@ -558,14 +560,11 @@ class Connection {
|
|
|
558
560
|
});
|
|
559
561
|
try {
|
|
560
562
|
pair.requestsSent++;
|
|
561
|
-
await pair.protocol.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"),
|
|
562
|
-
if (attempt > 0) {
|
|
563
|
-
pair.retransmissionsSent++;
|
|
564
|
-
}
|
|
565
|
-
});
|
|
563
|
+
await pair.protocol.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"), this.checkRequestOptions(pair));
|
|
566
564
|
pair.responsesReceived++;
|
|
567
565
|
}
|
|
568
566
|
catch (error) {
|
|
567
|
+
this.nominating = false;
|
|
569
568
|
pair.updateState(iceBase_1.CandidatePairState.FAILED);
|
|
570
569
|
this.checkComplete(pair);
|
|
571
570
|
return;
|
|
@@ -594,15 +593,55 @@ class Connection {
|
|
|
594
593
|
if (this.iceLite) {
|
|
595
594
|
this._iceControlling = false;
|
|
596
595
|
}
|
|
597
|
-
|
|
598
|
-
this.stunServer = (0, iceBase_1.validateAddress)(stunServer) ?? [
|
|
599
|
-
"stun.l.google.com",
|
|
600
|
-
19302,
|
|
601
|
-
];
|
|
602
|
-
this.turnServer = (0, iceBase_1.validateAddress)(turnServer);
|
|
596
|
+
this.applyStunTurnServersFromOptions();
|
|
603
597
|
this.restart();
|
|
604
598
|
log("new Connection", this.options);
|
|
605
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Replace STUN/TURN servers after construction.
|
|
602
|
+
* Server-related fields are replaced (not partial-merged) so that removing
|
|
603
|
+
* TURN clears residual credentials. W3C setConfiguration replaces the ICE
|
|
604
|
+
* server list rather than merging additively.
|
|
605
|
+
*
|
|
606
|
+
* Used when servers are learned after the gatherer was built (e.g. WHIP
|
|
607
|
+
* Link headers) and must take effect before the next gather pass.
|
|
608
|
+
*/
|
|
609
|
+
setIceServers(options) {
|
|
610
|
+
// Explicitly assign server fields even when undefined so a STUN-only
|
|
611
|
+
// update cannot leave a previous TURN host/credential in options.
|
|
612
|
+
this.options = {
|
|
613
|
+
...this.options,
|
|
614
|
+
stunServer: options.stunServer,
|
|
615
|
+
turnServer: options.turnServer,
|
|
616
|
+
turnUsername: options.turnUsername,
|
|
617
|
+
turnPassword: options.turnPassword,
|
|
618
|
+
turnTransport: options.turnTransport,
|
|
619
|
+
};
|
|
620
|
+
if (options.forceTurn !== undefined) {
|
|
621
|
+
this.options.forceTurn = options.forceTurn;
|
|
622
|
+
}
|
|
623
|
+
if (options.useTcp !== undefined) {
|
|
624
|
+
this.options.useTcp = options.useTcp;
|
|
625
|
+
}
|
|
626
|
+
if (options.turnTlsOptions !== undefined) {
|
|
627
|
+
this.options.turnTlsOptions = options.turnTlsOptions;
|
|
628
|
+
}
|
|
629
|
+
if (options.turnUdpFamily !== undefined) {
|
|
630
|
+
this.options.turnUdpFamily = options.turnUdpFamily;
|
|
631
|
+
}
|
|
632
|
+
this.applyStunTurnServersFromOptions();
|
|
633
|
+
log("Connection ice servers updated", this.options);
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Derive Connection.stunServer / turnServer from this.options.
|
|
637
|
+
* Shared by the constructor and setIceServers so both paths validate and
|
|
638
|
+
* default identically.
|
|
639
|
+
*/
|
|
640
|
+
applyStunTurnServersFromOptions() {
|
|
641
|
+
this.stunServer =
|
|
642
|
+
(0, iceBase_1.validateAddress)(this.options.stunServer) ?? DEFAULT_STUN_SERVER;
|
|
643
|
+
this.turnServer = (0, iceBase_1.validateAddress)(this.options.turnServer);
|
|
644
|
+
}
|
|
606
645
|
get iceControlling() {
|
|
607
646
|
return this._iceControlling;
|
|
608
647
|
}
|
|
@@ -698,7 +737,7 @@ class Connection {
|
|
|
698
737
|
if (this.options.additionalHostAddresses) {
|
|
699
738
|
address = Array.from(new Set([...this.options.additionalHostAddresses, ...address]));
|
|
700
739
|
}
|
|
701
|
-
const candidatePromises = this.getCandidatePromises(address,
|
|
740
|
+
const candidatePromises = this.getCandidatePromises(address, this.options.stunGatherTimeout);
|
|
702
741
|
await Promise.allSettled(candidatePromises);
|
|
703
742
|
this.localCandidatesEnd = true;
|
|
704
743
|
}
|
|
@@ -775,6 +814,29 @@ class Connection {
|
|
|
775
814
|
log("dataReceived", error);
|
|
776
815
|
}
|
|
777
816
|
});
|
|
817
|
+
protocol.onConnectionClosed?.subscribe((remoteAddr) => {
|
|
818
|
+
this.handleConnectionClosed(protocol, remoteAddr);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* RFC 6544: the selected TCP connection is the only path for this component;
|
|
823
|
+
* once it is closed no application data or consent check can reach the peer,
|
|
824
|
+
* so fail the same way as a consent expiry instead of waiting for it.
|
|
825
|
+
*/
|
|
826
|
+
handleConnectionClosed(protocol, remoteAddr) {
|
|
827
|
+
const nominated = this.nominated;
|
|
828
|
+
if (!nominated ||
|
|
829
|
+
nominated.protocol !== protocol ||
|
|
830
|
+
nominated.remoteAddr[0] !== remoteAddr[0] ||
|
|
831
|
+
nominated.remoteAddr[1] !== remoteAddr[1]) {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
if (this.state === "closed" || this.state === "failed") {
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
log("selected tcp connection closed", nominated.toJSON());
|
|
838
|
+
this.stopConsentLifecycle();
|
|
839
|
+
this.setState("failed");
|
|
778
840
|
}
|
|
779
841
|
getCandidatePromises(addresses, timeout = 5) {
|
|
780
842
|
const candidatePromises = [];
|
|
@@ -823,16 +885,21 @@ class Connection {
|
|
|
823
885
|
}
|
|
824
886
|
if (!gatherRelayOnly && this.options.useTcp) {
|
|
825
887
|
const tcpCandidatePromises = addresses.map(async (address) => {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
888
|
+
// Passive candidates open a listening TCP server; skip them when the
|
|
889
|
+
// agent only makes outbound connections (tcpPassive === false). Active
|
|
890
|
+
// candidates below still dial out, so direct TCP egress is unaffected.
|
|
891
|
+
if (this.options.tcpPassive !== false) {
|
|
892
|
+
const passiveProtocol = new tcpProtocol_1.TcpPassiveProtocol();
|
|
893
|
+
this.ensureProtocol(passiveProtocol);
|
|
894
|
+
await passiveProtocol.connectionMade(address, this.options.portRange);
|
|
895
|
+
passiveProtocol.localIp = address;
|
|
896
|
+
passiveProtocol.localCandidate = new candidate_1.Candidate((0, candidate_1.candidateFoundation)("host", "tcp", address), 1, "tcp", (0, candidate_1.candidatePriority)("host", {
|
|
897
|
+
transport: "tcp",
|
|
898
|
+
tcptype: "passive",
|
|
899
|
+
}), address, passiveProtocol.listeningPort, "host", undefined, undefined, "passive", this.generation, this.localUsername);
|
|
900
|
+
this.protocols.push(passiveProtocol);
|
|
901
|
+
this.appendLocalCandidate(passiveProtocol.localCandidate);
|
|
902
|
+
}
|
|
836
903
|
if (!gatherIceLite) {
|
|
837
904
|
const activeProtocol = new tcpProtocol_1.TcpActiveProtocol();
|
|
838
905
|
this.ensureProtocol(activeProtocol);
|
|
@@ -890,6 +957,8 @@ class Connection {
|
|
|
890
957
|
interfaceAddresses: this.options.interfaceAddresses,
|
|
891
958
|
transport: turnTransport,
|
|
892
959
|
tlsOptions: this.options.turnTlsOptions,
|
|
960
|
+
connectTimeoutMs: (this.options.turnConnectTimeout ?? 8) * 1000,
|
|
961
|
+
udpFamily: this.options.turnUdpFamily,
|
|
893
962
|
}).catch(async (e) => {
|
|
894
963
|
if (turnTransport === "udp") {
|
|
895
964
|
return await (0, protocol_2.createStunOverTurnClient)({
|
|
@@ -900,6 +969,7 @@ class Connection {
|
|
|
900
969
|
portRange: this.options.portRange,
|
|
901
970
|
interfaceAddresses: this.options.interfaceAddresses,
|
|
902
971
|
transport: "tcp",
|
|
972
|
+
connectTimeoutMs: (this.options.turnConnectTimeout ?? 8) * 1000,
|
|
903
973
|
});
|
|
904
974
|
}
|
|
905
975
|
else {
|
|
@@ -1268,6 +1338,11 @@ class Connection {
|
|
|
1268
1338
|
}
|
|
1269
1339
|
}
|
|
1270
1340
|
}
|
|
1341
|
+
this.nominateTcpPairIfReady();
|
|
1342
|
+
// A nomination request is still in flight; its result decides the outcome.
|
|
1343
|
+
if (this.nominating) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1271
1346
|
{
|
|
1272
1347
|
const list = [iceBase_1.CandidatePairState.SUCCEEDED, iceBase_1.CandidatePairState.FAILED];
|
|
1273
1348
|
if (this.checkList.find(({ state }) => !list.includes(state))) {
|
|
@@ -1287,6 +1362,97 @@ class Connection {
|
|
|
1287
1362
|
}));
|
|
1288
1363
|
}
|
|
1289
1364
|
}
|
|
1365
|
+
isTcpPair(pair) {
|
|
1366
|
+
return pair.localCandidate.transport.toLowerCase() === "tcp";
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Aggressive nomination lets each side settle on whichever TCP connection
|
|
1370
|
+
* finished first; the two sides can then pick different connections and
|
|
1371
|
+
* pruning destroys the peer's choice. For TCP the controlling agent instead
|
|
1372
|
+
* nominates exactly one valid pair (RFC 8445 §8.1.1 regular nomination).
|
|
1373
|
+
*/
|
|
1374
|
+
usesTcpRegularNomination(pair) {
|
|
1375
|
+
return this.iceControlling && !this.remoteIsLite && this.isTcpPair(pair);
|
|
1376
|
+
}
|
|
1377
|
+
checkRequestOptions(pair) {
|
|
1378
|
+
const onRequestSent = (attempt) => {
|
|
1379
|
+
if (attempt > 0) {
|
|
1380
|
+
pair.retransmissionsSent++;
|
|
1381
|
+
}
|
|
1382
|
+
};
|
|
1383
|
+
if (this.isTcpPair(pair)) {
|
|
1384
|
+
// RFC 5389 §7.2.2: no retransmissions over a reliable transport.
|
|
1385
|
+
return {
|
|
1386
|
+
retransmissions: 0,
|
|
1387
|
+
responseTimeout: const_1.TCP_CHECK_RESPONSE_TIMEOUT_MS,
|
|
1388
|
+
onRequestSent,
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
return { retransmissions: 4, onRequestSent };
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Controlling side: nominate the highest-priority TCP pair once every
|
|
1395
|
+
* higher-priority TCP pair has finished its check, so the choice does not
|
|
1396
|
+
* depend on which connection happened to complete first.
|
|
1397
|
+
*/
|
|
1398
|
+
nominateTcpPairIfReady() {
|
|
1399
|
+
if (!this.iceControlling ||
|
|
1400
|
+
this.remoteIsLite ||
|
|
1401
|
+
this.nominated ||
|
|
1402
|
+
this.nominating) {
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
for (const pair of this.checkList) {
|
|
1406
|
+
if (!this.isTcpPair(pair)) {
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
if (pair.state === iceBase_1.CandidatePairState.SUCCEEDED) {
|
|
1410
|
+
this.nominateTcpPair(pair);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
if (pair.state !== iceBase_1.CandidatePairState.FAILED) {
|
|
1414
|
+
// A higher-priority pair may still succeed.
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
nominateTcpPair(pair) {
|
|
1420
|
+
this.nominating = true;
|
|
1421
|
+
const { generation } = this;
|
|
1422
|
+
const request = this.buildRequest({
|
|
1423
|
+
nominate: true,
|
|
1424
|
+
localUsername: pair.localCandidate.ufrag ?? this.localUsername,
|
|
1425
|
+
remoteUsername: this.remoteUsername,
|
|
1426
|
+
iceControlling: this.iceControlling,
|
|
1427
|
+
localCandidate: pair.localCandidate,
|
|
1428
|
+
});
|
|
1429
|
+
pair.requestsSent++;
|
|
1430
|
+
pair.protocol
|
|
1431
|
+
.request(request, pair.remoteAddr, Buffer.from(this.remotePassword, "utf8"), this.checkRequestOptions(pair))
|
|
1432
|
+
.then(() => {
|
|
1433
|
+
if (this.isStaleNomination(pair, generation)) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
pair.responsesReceived++;
|
|
1437
|
+
pair.nominated = true;
|
|
1438
|
+
this.nominating = false;
|
|
1439
|
+
this.checkComplete(pair);
|
|
1440
|
+
}, (error) => {
|
|
1441
|
+
if (this.isStaleNomination(pair, generation)) {
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
log("tcp nomination failed", pair.toJSON(), error);
|
|
1445
|
+
this.nominating = false;
|
|
1446
|
+
pair.updateState(iceBase_1.CandidatePairState.FAILED);
|
|
1447
|
+
this.checkComplete(pair);
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
/** The agent was closed or restarted while the nomination was in flight. */
|
|
1451
|
+
isStaleNomination(pair, generation) {
|
|
1452
|
+
return (this.state === "closed" ||
|
|
1453
|
+
this.generation !== generation ||
|
|
1454
|
+
!this.checkList.includes(pair));
|
|
1455
|
+
}
|
|
1290
1456
|
addPair(pair) {
|
|
1291
1457
|
this.checkList.push(pair);
|
|
1292
1458
|
this.sortCheckList();
|