node-rtc-connection 1.0.19 → 2.0.4
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 +94 -85
- package/dist/index.cjs +20 -5606
- package/dist/index.mjs +25 -5598
- package/dist/types/crypto/der.d.ts +107 -0
- package/dist/types/crypto/x509.d.ts +56 -0
- package/dist/types/datachannel/RTCDataChannel.d.ts +179 -0
- package/dist/types/dtls/RTCCertificate.d.ts +163 -0
- package/dist/types/dtls/cipher.d.ts +81 -0
- package/dist/types/dtls/connection.d.ts +81 -0
- package/dist/types/dtls/prf.d.ts +29 -0
- package/dist/types/dtls/protocol.d.ts +127 -0
- package/dist/types/foundation/ByteBufferQueue.d.ts +71 -0
- package/dist/types/foundation/RTCError.d.ts +152 -0
- package/dist/types/ice/RTCIceCandidate.d.ts +161 -0
- package/dist/types/ice/ice-agent.d.ts +154 -0
- package/dist/types/ice/stun-message.d.ts +92 -0
- package/dist/types/index.d.ts +29 -0
- package/dist/types/peerconnection/RTCPeerConnection.d.ts +74 -0
- package/dist/types/sctp/association.d.ts +77 -0
- package/dist/types/sctp/chunks.d.ts +200 -0
- package/dist/types/sctp/crc32c.d.ts +24 -0
- package/dist/types/sctp/datachannel-manager.d.ts +51 -0
- package/dist/types/sctp/dcep.d.ts +56 -0
- package/dist/types/sdp/RTCSessionDescription.d.ts +73 -0
- package/dist/types/sdp/sdp-utils.d.ts +103 -0
- package/dist/types/stun/stun-client.d.ts +119 -0
- package/dist/types/transport-stack.d.ts +68 -0
- package/package.json +26 -21
- package/src/crypto/der.ts +205 -0
- package/src/crypto/x509.ts +146 -0
- package/src/datachannel/RTCDataChannel.ts +388 -0
- package/src/dtls/RTCCertificate.ts +396 -0
- package/src/dtls/cipher.ts +198 -0
- package/src/dtls/connection.ts +974 -0
- package/src/dtls/prf.ts +62 -0
- package/src/dtls/protocol.ts +204 -0
- package/src/foundation/{ByteBufferQueue.js → ByteBufferQueue.ts} +74 -72
- package/src/foundation/{RTCError.js → RTCError.ts} +110 -60
- package/src/ice/{RTCIceCandidate.js → RTCIceCandidate.ts} +140 -92
- package/src/ice/ice-agent.ts +609 -0
- package/src/ice/stun-message.ts +260 -0
- package/src/index.ts +72 -0
- package/src/peerconnection/RTCPeerConnection.ts +430 -0
- package/src/sctp/association.ts +523 -0
- package/src/sctp/chunks.ts +350 -0
- package/src/sctp/crc32c.ts +57 -0
- package/src/sctp/datachannel-manager.ts +187 -0
- package/src/sctp/dcep.ts +94 -0
- package/src/sdp/{RTCSessionDescription.js → RTCSessionDescription.ts} +42 -29
- package/src/sdp/sdp-utils.ts +229 -0
- package/src/stun/{stun-client.js → stun-client.ts} +346 -187
- package/src/transport-stack.ts +165 -0
- package/dist/index.cjs.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/src/datachannel/RTCDataChannel.js +0 -354
- package/src/dtls/RTCCertificate.js +0 -310
- package/src/dtls/RTCDtlsTransport.js +0 -247
- package/src/ice/RTCIceTransport.js +0 -1018
- package/src/index.d.ts +0 -400
- package/src/index.js +0 -92
- package/src/network/network-transport.js +0 -478
- package/src/peerconnection/RTCPeerConnection.js +0 -875
- package/src/sctp/RTCSctpTransport.js +0 -253
- package/src/sdp/sdp-utils.js +0 -224
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file protocol.ts
|
|
3
|
+
* @description DTLS 1.2 wire-format constants and TLV/vector encoders.
|
|
4
|
+
* @module dtls/protocol
|
|
5
|
+
*
|
|
6
|
+
* Covers exactly what WebRTC's data channel needs:
|
|
7
|
+
* cipher suite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xC02B)
|
|
8
|
+
* curve secp256r1, signature scheme ecdsa_secp256r1_sha256.
|
|
9
|
+
*
|
|
10
|
+
* References: RFC 6347 (DTLS 1.2), RFC 5246 (TLS 1.2), RFC 8422 (ECC).
|
|
11
|
+
*/
|
|
12
|
+
export declare const DTLS_1_2 = 65277;
|
|
13
|
+
export declare const CONTENT_TYPE: Readonly<{
|
|
14
|
+
CHANGE_CIPHER_SPEC: 20;
|
|
15
|
+
ALERT: 21;
|
|
16
|
+
HANDSHAKE: 22;
|
|
17
|
+
APPLICATION_DATA: 23;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const HANDSHAKE_TYPE: Readonly<{
|
|
20
|
+
HELLO_REQUEST: 0;
|
|
21
|
+
CLIENT_HELLO: 1;
|
|
22
|
+
SERVER_HELLO: 2;
|
|
23
|
+
HELLO_VERIFY_REQUEST: 3;
|
|
24
|
+
CERTIFICATE: 11;
|
|
25
|
+
SERVER_KEY_EXCHANGE: 12;
|
|
26
|
+
CERTIFICATE_REQUEST: 13;
|
|
27
|
+
SERVER_HELLO_DONE: 14;
|
|
28
|
+
CERTIFICATE_VERIFY: 15;
|
|
29
|
+
CLIENT_KEY_EXCHANGE: 16;
|
|
30
|
+
FINISHED: 20;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const ALERT_LEVEL: Readonly<{
|
|
33
|
+
WARNING: 1;
|
|
34
|
+
FATAL: 2;
|
|
35
|
+
}>;
|
|
36
|
+
export declare const ALERT_DESC: Readonly<{
|
|
37
|
+
CLOSE_NOTIFY: 0;
|
|
38
|
+
HANDSHAKE_FAILURE: 40;
|
|
39
|
+
BAD_CERTIFICATE: 42;
|
|
40
|
+
DECRYPT_ERROR: 51;
|
|
41
|
+
INTERNAL_ERROR: 80;
|
|
42
|
+
}>;
|
|
43
|
+
export declare const CIPHER_SUITE = 49195;
|
|
44
|
+
export declare const NAMED_GROUP: Readonly<{
|
|
45
|
+
secp256r1: 23;
|
|
46
|
+
}>;
|
|
47
|
+
export declare const EC_POINT_FORMAT: Readonly<{
|
|
48
|
+
uncompressed: 0;
|
|
49
|
+
}>;
|
|
50
|
+
export declare const HASH_ALG: Readonly<{
|
|
51
|
+
sha256: 4;
|
|
52
|
+
sha384: 5;
|
|
53
|
+
sha512: 6;
|
|
54
|
+
}>;
|
|
55
|
+
export declare const SIG_ALG: Readonly<{
|
|
56
|
+
rsa: 1;
|
|
57
|
+
ecdsa: 3;
|
|
58
|
+
}>;
|
|
59
|
+
export declare const CERT_TYPE: Readonly<{
|
|
60
|
+
ecdsa_sign: 64;
|
|
61
|
+
rsa_sign: 1;
|
|
62
|
+
}>;
|
|
63
|
+
export declare const EXTENSION: Readonly<{
|
|
64
|
+
SUPPORTED_GROUPS: 10;
|
|
65
|
+
EC_POINT_FORMATS: 11;
|
|
66
|
+
SIGNATURE_ALGORITHMS: 13;
|
|
67
|
+
EXTENDED_MASTER_SECRET: 23;
|
|
68
|
+
RENEGOTIATION_INFO: 65281;
|
|
69
|
+
}>;
|
|
70
|
+
export declare const FINISHED_LABEL: Readonly<{
|
|
71
|
+
CLIENT: "client finished";
|
|
72
|
+
SERVER: "server finished";
|
|
73
|
+
}>;
|
|
74
|
+
/** A parsed DTLS record from {@link parseRecords}. */
|
|
75
|
+
export interface Record {
|
|
76
|
+
type: number;
|
|
77
|
+
version: number;
|
|
78
|
+
epoch: number;
|
|
79
|
+
seq: number;
|
|
80
|
+
fragment: Buffer;
|
|
81
|
+
}
|
|
82
|
+
/** A parsed handshake message header from {@link parseHandshake}. */
|
|
83
|
+
export interface Handshake {
|
|
84
|
+
msgType: number;
|
|
85
|
+
length: number;
|
|
86
|
+
messageSeq: number;
|
|
87
|
+
fragmentOffset: number;
|
|
88
|
+
fragmentLength: number;
|
|
89
|
+
body: Buffer;
|
|
90
|
+
}
|
|
91
|
+
/** Encode a uint24 (3 bytes, big-endian). */
|
|
92
|
+
export declare function uint24(n: number): Buffer;
|
|
93
|
+
/** Read a uint24 at offset. */
|
|
94
|
+
export declare function readUint24(buf: Buffer, off: number): number;
|
|
95
|
+
/** Length-prefixed vector with a 1-byte length. */
|
|
96
|
+
export declare function vec8(body: Buffer): Buffer;
|
|
97
|
+
/** Length-prefixed vector with a 2-byte length. */
|
|
98
|
+
export declare function vec16(body: Buffer): Buffer;
|
|
99
|
+
/** Length-prefixed vector with a 3-byte length. */
|
|
100
|
+
export declare function vec24(body: Buffer): Buffer;
|
|
101
|
+
/**
|
|
102
|
+
* Encode a DTLS record (13-byte header + fragment).
|
|
103
|
+
* @param type - CONTENT_TYPE
|
|
104
|
+
* @param epoch
|
|
105
|
+
* @param seq - 48-bit sequence number
|
|
106
|
+
* @param fragment
|
|
107
|
+
* @param version
|
|
108
|
+
*/
|
|
109
|
+
export declare function encodeRecord(type: number, epoch: number, seq: number, fragment: Buffer, version?: number): Buffer;
|
|
110
|
+
/**
|
|
111
|
+
* Parse one or more DTLS records from a datagram. Multiple records may be
|
|
112
|
+
* packed into a single UDP packet.
|
|
113
|
+
* @param packet
|
|
114
|
+
*/
|
|
115
|
+
export declare function parseRecords(packet: Buffer): Record[];
|
|
116
|
+
/**
|
|
117
|
+
* Encode a DTLS handshake message header + body (unfragmented).
|
|
118
|
+
* @param msgType - HANDSHAKE_TYPE
|
|
119
|
+
* @param messageSeq
|
|
120
|
+
* @param body
|
|
121
|
+
*/
|
|
122
|
+
export declare function encodeHandshake(msgType: number, messageSeq: number, body: Buffer): Buffer;
|
|
123
|
+
/**
|
|
124
|
+
* Parse a handshake message header.
|
|
125
|
+
* @param buf - starts at the handshake header
|
|
126
|
+
*/
|
|
127
|
+
export declare function parseHandshake(buf: Buffer): Handshake;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ByteBufferQueue - Efficient byte buffer with O(1) append and O(n) read.
|
|
3
|
+
*
|
|
4
|
+
* This class provides efficient management of byte buffers with O(1) append operations
|
|
5
|
+
* and O(n) read operations. Clients can append entire buffers then copy data out across
|
|
6
|
+
* buffer boundaries.
|
|
7
|
+
*
|
|
8
|
+
* @license MIT
|
|
9
|
+
* @author nmhung1210
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A ByteBufferQueue manages a queue of byte buffers with efficient operations.
|
|
13
|
+
*
|
|
14
|
+
* Invariants maintained:
|
|
15
|
+
* - size_ = sum of all buffer sizes - frontBufferOffset_
|
|
16
|
+
* - No buffer in the queue is empty
|
|
17
|
+
* - If queue is empty, frontBufferOffset_ = 0
|
|
18
|
+
* - Otherwise, frontBufferOffset_ < front buffer size
|
|
19
|
+
*/
|
|
20
|
+
declare class ByteBufferQueue {
|
|
21
|
+
#private;
|
|
22
|
+
constructor();
|
|
23
|
+
/**
|
|
24
|
+
* Number of bytes that can be read.
|
|
25
|
+
* @returns {number}
|
|
26
|
+
*/
|
|
27
|
+
get size(): number;
|
|
28
|
+
/**
|
|
29
|
+
* Returns true if no bytes are available to read.
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
get empty(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Copies data into the given buffer. Consumes bytes from the queue.
|
|
35
|
+
* Returns the number of bytes written to bufferOut.
|
|
36
|
+
*
|
|
37
|
+
* @param {Buffer} bufferOut - Destination buffer to read into
|
|
38
|
+
* @returns {number} Number of bytes actually read
|
|
39
|
+
* @throws {TypeError} If bufferOut is not a Buffer
|
|
40
|
+
*/
|
|
41
|
+
readInto(bufferOut: Buffer): number;
|
|
42
|
+
/**
|
|
43
|
+
* Appends a buffer to the queue. Takes ownership of the buffer.
|
|
44
|
+
* Empty buffers are ignored.
|
|
45
|
+
*
|
|
46
|
+
* @param {Buffer} buffer - Buffer to append
|
|
47
|
+
* @throws {TypeError} If buffer is not a Buffer
|
|
48
|
+
*/
|
|
49
|
+
append(buffer: Buffer): void;
|
|
50
|
+
/**
|
|
51
|
+
* Clears all stored buffers.
|
|
52
|
+
*/
|
|
53
|
+
clear(): void;
|
|
54
|
+
/**
|
|
55
|
+
* Reads and consumes exactly n bytes.
|
|
56
|
+
*
|
|
57
|
+
* @param {number} n - Number of bytes to read
|
|
58
|
+
* @returns {Buffer} Buffer containing exactly n bytes
|
|
59
|
+
* @throws {RangeError} If fewer than n bytes are available
|
|
60
|
+
*/
|
|
61
|
+
read(n: number): Buffer;
|
|
62
|
+
/**
|
|
63
|
+
* Peeks at data without consuming it.
|
|
64
|
+
*
|
|
65
|
+
* @param {number} [n=this.#size] - Number of bytes to peek
|
|
66
|
+
* @returns {Buffer} Buffer containing up to n bytes (not consumed)
|
|
67
|
+
*/
|
|
68
|
+
peek(n?: number): Buffer;
|
|
69
|
+
}
|
|
70
|
+
export default ByteBufferQueue;
|
|
71
|
+
export { ByteBufferQueue };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file RTCError - WebRTC-specific error types.
|
|
3
|
+
*
|
|
4
|
+
* Implements the W3C RTCError interface
|
|
5
|
+
* (https://www.w3.org/TR/webrtc/#rtcerror-interface).
|
|
6
|
+
*
|
|
7
|
+
* Provides WebRTC-specific error types extending the standard Error class
|
|
8
|
+
* with additional error detail types and metadata fields.
|
|
9
|
+
*
|
|
10
|
+
* @license MIT
|
|
11
|
+
* @author nmhung1210
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* RTCErrorDetailType enum - Standardized WebRTC error details.
|
|
15
|
+
* Maps to RTCErrorDetailType from the WebRTC spec.
|
|
16
|
+
*
|
|
17
|
+
* @readonly
|
|
18
|
+
* @enum {string}
|
|
19
|
+
*/
|
|
20
|
+
declare const RTCErrorDetailType: Readonly<{
|
|
21
|
+
readonly NONE: "none";
|
|
22
|
+
readonly DATA_CHANNEL_FAILURE: "data-channel-failure";
|
|
23
|
+
readonly DTLS_FAILURE: "dtls-failure";
|
|
24
|
+
readonly FINGERPRINT_FAILURE: "fingerprint-failure";
|
|
25
|
+
readonly SCTP_FAILURE: "sctp-failure";
|
|
26
|
+
readonly SDP_SYNTAX_ERROR: "sdp-syntax-error";
|
|
27
|
+
readonly HARDWARE_ENCODER_NOT_AVAILABLE: "hardware-encoder-not-available";
|
|
28
|
+
readonly HARDWARE_ENCODER_ERROR: "hardware-encoder-error";
|
|
29
|
+
readonly INVALID_STATE: "invalid-state";
|
|
30
|
+
readonly INVALID_MODIFICATION: "invalid-modification";
|
|
31
|
+
readonly INVALID_ACCESS_ERROR: "invalid-access-error";
|
|
32
|
+
readonly OPERATION_ERROR: "operation-error";
|
|
33
|
+
}>;
|
|
34
|
+
/**
|
|
35
|
+
* Error detail type string union.
|
|
36
|
+
*/
|
|
37
|
+
type RTCErrorDetail = typeof RTCErrorDetailType[keyof typeof RTCErrorDetailType];
|
|
38
|
+
/**
|
|
39
|
+
* Error initialization dictionary.
|
|
40
|
+
*/
|
|
41
|
+
interface RTCErrorInit {
|
|
42
|
+
errorDetail?: string;
|
|
43
|
+
sdpLineNumber?: number | null;
|
|
44
|
+
httpRequestStatusCode?: number | null;
|
|
45
|
+
sctpCauseCode?: number | null;
|
|
46
|
+
receivedAlert?: number | null;
|
|
47
|
+
sentAlert?: number | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Native WebRTC error object shape.
|
|
51
|
+
*/
|
|
52
|
+
interface NativeRTCError {
|
|
53
|
+
error_detail?: string;
|
|
54
|
+
sctp_cause_code?: number;
|
|
55
|
+
message?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* JSON representation of an RTCError.
|
|
59
|
+
*/
|
|
60
|
+
interface RTCErrorJSON {
|
|
61
|
+
name: string;
|
|
62
|
+
message: string;
|
|
63
|
+
errorDetail: string;
|
|
64
|
+
sdpLineNumber?: number;
|
|
65
|
+
httpRequestStatusCode?: number;
|
|
66
|
+
sctpCauseCode?: number;
|
|
67
|
+
receivedAlert?: number;
|
|
68
|
+
sentAlert?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* RTCError extends Error with WebRTC-specific error details.
|
|
72
|
+
*
|
|
73
|
+
* @extends Error
|
|
74
|
+
*/
|
|
75
|
+
declare class RTCError extends Error {
|
|
76
|
+
#private;
|
|
77
|
+
/** Export error detail types as static property */
|
|
78
|
+
static readonly DetailType: Readonly<{
|
|
79
|
+
readonly NONE: "none";
|
|
80
|
+
readonly DATA_CHANNEL_FAILURE: "data-channel-failure";
|
|
81
|
+
readonly DTLS_FAILURE: "dtls-failure";
|
|
82
|
+
readonly FINGERPRINT_FAILURE: "fingerprint-failure";
|
|
83
|
+
readonly SCTP_FAILURE: "sctp-failure";
|
|
84
|
+
readonly SDP_SYNTAX_ERROR: "sdp-syntax-error";
|
|
85
|
+
readonly HARDWARE_ENCODER_NOT_AVAILABLE: "hardware-encoder-not-available";
|
|
86
|
+
readonly HARDWARE_ENCODER_ERROR: "hardware-encoder-error";
|
|
87
|
+
readonly INVALID_STATE: "invalid-state";
|
|
88
|
+
readonly INVALID_MODIFICATION: "invalid-modification";
|
|
89
|
+
readonly INVALID_ACCESS_ERROR: "invalid-access-error";
|
|
90
|
+
readonly OPERATION_ERROR: "operation-error";
|
|
91
|
+
}>;
|
|
92
|
+
/**
|
|
93
|
+
* Creates a new RTCError.
|
|
94
|
+
*
|
|
95
|
+
* @param {RTCErrorInit} [init={}] - Error initialization dictionary
|
|
96
|
+
* @param {string} [init.errorDetail='none'] - Error detail type
|
|
97
|
+
* @param {number} [init.sdpLineNumber] - SDP line number where error occurred
|
|
98
|
+
* @param {number} [init.httpRequestStatusCode] - HTTP status code if relevant
|
|
99
|
+
* @param {number} [init.sctpCauseCode] - SCTP cause code
|
|
100
|
+
* @param {number} [init.receivedAlert] - TLS alert received
|
|
101
|
+
* @param {number} [init.sentAlert] - TLS alert sent
|
|
102
|
+
* @param {string} [message=''] - Error message
|
|
103
|
+
*/
|
|
104
|
+
constructor(init?: RTCErrorInit, message?: string);
|
|
105
|
+
/**
|
|
106
|
+
* RTCErrorDetailType - specific error category.
|
|
107
|
+
* @type {string}
|
|
108
|
+
*/
|
|
109
|
+
get errorDetail(): string;
|
|
110
|
+
/**
|
|
111
|
+
* SDP line number where the error occurred (if applicable).
|
|
112
|
+
* @type {number|null}
|
|
113
|
+
*/
|
|
114
|
+
get sdpLineNumber(): number | null;
|
|
115
|
+
/**
|
|
116
|
+
* HTTP request status code (if applicable).
|
|
117
|
+
* @type {number|null}
|
|
118
|
+
*/
|
|
119
|
+
get httpRequestStatusCode(): number | null;
|
|
120
|
+
/**
|
|
121
|
+
* SCTP cause code (if applicable).
|
|
122
|
+
* @type {number|null}
|
|
123
|
+
*/
|
|
124
|
+
get sctpCauseCode(): number | null;
|
|
125
|
+
/**
|
|
126
|
+
* TLS alert value received (if applicable).
|
|
127
|
+
* @type {number|null}
|
|
128
|
+
*/
|
|
129
|
+
get receivedAlert(): number | null;
|
|
130
|
+
/**
|
|
131
|
+
* TLS alert value sent (if applicable).
|
|
132
|
+
* @type {number|null}
|
|
133
|
+
*/
|
|
134
|
+
get sentAlert(): number | null;
|
|
135
|
+
/**
|
|
136
|
+
* Converts error to JSON representation.
|
|
137
|
+
* @returns {Object} JSON representation of the error
|
|
138
|
+
*/
|
|
139
|
+
toJSON(): RTCErrorJSON;
|
|
140
|
+
/**
|
|
141
|
+
* Creates RTCError from a native WebRTC error object.
|
|
142
|
+
* @param {Object} nativeError - Native error object
|
|
143
|
+
* @param {string} [nativeError.error_detail] - Error detail type
|
|
144
|
+
* @param {number} [nativeError.sctp_cause_code] - SCTP cause code
|
|
145
|
+
* @param {string} [nativeError.message] - Error message
|
|
146
|
+
* @returns {RTCError}
|
|
147
|
+
*/
|
|
148
|
+
static fromNative(nativeError: NativeRTCError): RTCError;
|
|
149
|
+
}
|
|
150
|
+
export default RTCError;
|
|
151
|
+
export { RTCError, RTCErrorDetailType };
|
|
152
|
+
export type { RTCErrorInit, RTCErrorDetail, NativeRTCError, RTCErrorJSON };
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file RTCIceCandidate - ICE candidate representation.
|
|
3
|
+
*
|
|
4
|
+
* Implements the W3C RTCIceCandidate interface
|
|
5
|
+
* (https://www.w3.org/TR/webrtc/#rtcicecandidate-interface).
|
|
6
|
+
*
|
|
7
|
+
* Represents an ICE (Interactive Connectivity Establishment) candidate that
|
|
8
|
+
* describes a potential way to establish a connection with a peer.
|
|
9
|
+
*
|
|
10
|
+
* @license MIT
|
|
11
|
+
* @author nmhung1210
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Initialization dictionary for RTCIceCandidate.
|
|
15
|
+
*/
|
|
16
|
+
interface RTCIceCandidateInit {
|
|
17
|
+
candidate?: string;
|
|
18
|
+
sdpMid?: string | null;
|
|
19
|
+
sdpMLineIndex?: number | null;
|
|
20
|
+
usernameFragment?: string | null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parsed attributes extracted from an ICE candidate string.
|
|
24
|
+
*/
|
|
25
|
+
interface ParsedCandidateAttributes {
|
|
26
|
+
foundation: string | null;
|
|
27
|
+
component: string | null;
|
|
28
|
+
protocol: string | null;
|
|
29
|
+
priority: number | null;
|
|
30
|
+
address: string | null;
|
|
31
|
+
port: number | null;
|
|
32
|
+
type: string | null;
|
|
33
|
+
tcpType: string | null;
|
|
34
|
+
relatedAddress: string | null;
|
|
35
|
+
relatedPort: number | null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* JSON representation of an RTCIceCandidate.
|
|
39
|
+
*/
|
|
40
|
+
interface RTCIceCandidateJSON {
|
|
41
|
+
candidate: string;
|
|
42
|
+
sdpMid: string | null;
|
|
43
|
+
sdpMLineIndex: number | null;
|
|
44
|
+
usernameFragment?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* RTCIceCandidate represents a potential method for establishing connectivity.
|
|
48
|
+
*
|
|
49
|
+
* ICE candidates are described using SDP (Session Description Protocol) syntax.
|
|
50
|
+
* Each candidate describes a single address/port combination and transport protocol.
|
|
51
|
+
*/
|
|
52
|
+
declare class RTCIceCandidate {
|
|
53
|
+
#private;
|
|
54
|
+
/**
|
|
55
|
+
* Creates a new RTCIceCandidate.
|
|
56
|
+
*
|
|
57
|
+
* @param {RTCIceCandidateInit} [candidateInit={}] - Initialization dictionary
|
|
58
|
+
* @param {string} [candidateInit.candidate=''] - SDP candidate string
|
|
59
|
+
* @param {string|null} [candidateInit.sdpMid] - Media stream ID
|
|
60
|
+
* @param {number|null} [candidateInit.sdpMLineIndex] - M-line index
|
|
61
|
+
* @param {string} [candidateInit.usernameFragment] - ICE username fragment
|
|
62
|
+
* @throws {TypeError} If both sdpMid and sdpMLineIndex are null
|
|
63
|
+
*/
|
|
64
|
+
constructor(candidateInit?: RTCIceCandidateInit);
|
|
65
|
+
/**
|
|
66
|
+
* SDP candidate attribute containing the candidate description.
|
|
67
|
+
* @type {string}
|
|
68
|
+
*/
|
|
69
|
+
get candidate(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Media stream identification tag.
|
|
72
|
+
* @type {string|null}
|
|
73
|
+
*/
|
|
74
|
+
get sdpMid(): string | null;
|
|
75
|
+
/**
|
|
76
|
+
* Index of the m-line in the SDP this candidate is associated with.
|
|
77
|
+
* @type {number|null}
|
|
78
|
+
*/
|
|
79
|
+
get sdpMLineIndex(): number | null;
|
|
80
|
+
/**
|
|
81
|
+
* ICE username fragment.
|
|
82
|
+
* @type {string|null}
|
|
83
|
+
*/
|
|
84
|
+
get usernameFragment(): string | null;
|
|
85
|
+
/**
|
|
86
|
+
* Unique identifier for this candidate.
|
|
87
|
+
* @type {string|null}
|
|
88
|
+
*/
|
|
89
|
+
get foundation(): string | null;
|
|
90
|
+
/**
|
|
91
|
+
* Component identifier (rtp=1, rtcp=2).
|
|
92
|
+
* @type {string|null}
|
|
93
|
+
*/
|
|
94
|
+
get component(): string | null;
|
|
95
|
+
/**
|
|
96
|
+
* Priority value for this candidate.
|
|
97
|
+
* Higher priority candidates are preferred.
|
|
98
|
+
* @type {number|null}
|
|
99
|
+
*/
|
|
100
|
+
get priority(): number | null;
|
|
101
|
+
/**
|
|
102
|
+
* IP address of this candidate.
|
|
103
|
+
* @type {string|null}
|
|
104
|
+
*/
|
|
105
|
+
get address(): string | null;
|
|
106
|
+
/**
|
|
107
|
+
* Transport protocol (udp/tcp).
|
|
108
|
+
* @type {string|null}
|
|
109
|
+
*/
|
|
110
|
+
get protocol(): string | null;
|
|
111
|
+
/**
|
|
112
|
+
* Port number.
|
|
113
|
+
* @type {number|null}
|
|
114
|
+
*/
|
|
115
|
+
get port(): number | null;
|
|
116
|
+
/**
|
|
117
|
+
* Type of candidate (host, srflx, prflx, relay).
|
|
118
|
+
* @type {string|null}
|
|
119
|
+
*/
|
|
120
|
+
get type(): string | null;
|
|
121
|
+
/**
|
|
122
|
+
* TCP candidate type (active, passive, so).
|
|
123
|
+
* Only applicable for TCP candidates.
|
|
124
|
+
* @type {string|null}
|
|
125
|
+
*/
|
|
126
|
+
get tcpType(): string | null;
|
|
127
|
+
/**
|
|
128
|
+
* Related address for reflexive/relay candidates.
|
|
129
|
+
* @type {string|null}
|
|
130
|
+
*/
|
|
131
|
+
get relatedAddress(): string | null;
|
|
132
|
+
/**
|
|
133
|
+
* Related port for reflexive/relay candidates.
|
|
134
|
+
* @type {number|null}
|
|
135
|
+
*/
|
|
136
|
+
get relatedPort(): number | null;
|
|
137
|
+
/**
|
|
138
|
+
* Converts candidate to JSON representation.
|
|
139
|
+
* @returns {Object} JSON representation
|
|
140
|
+
*/
|
|
141
|
+
toJSON(): RTCIceCandidateJSON;
|
|
142
|
+
/**
|
|
143
|
+
* Creates an RTCIceCandidate from a candidate string.
|
|
144
|
+
*
|
|
145
|
+
* @param {string} candidateStr - ICE candidate string
|
|
146
|
+
* @param {string|null} [sdpMid=null] - Media stream ID
|
|
147
|
+
* @param {number|null} [sdpMLineIndex=0] - M-line index
|
|
148
|
+
* @returns {RTCIceCandidate}
|
|
149
|
+
*/
|
|
150
|
+
static fromString(candidateStr: string, sdpMid?: string | null, sdpMLineIndex?: number | null): RTCIceCandidate;
|
|
151
|
+
/**
|
|
152
|
+
* Validates if a string is a valid candidate format.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} candidateStr - String to validate
|
|
155
|
+
* @returns {boolean} True if valid candidate format
|
|
156
|
+
*/
|
|
157
|
+
static isValid(candidateStr: string): boolean;
|
|
158
|
+
}
|
|
159
|
+
export default RTCIceCandidate;
|
|
160
|
+
export { RTCIceCandidate };
|
|
161
|
+
export type { RTCIceCandidateInit, ParsedCandidateAttributes, RTCIceCandidateJSON };
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file ice-agent.ts
|
|
3
|
+
* @description A small but RFC 8445-compliant ICE agent for a single data
|
|
4
|
+
* component, with browser-compatible connectivity checks and TURN relay.
|
|
5
|
+
* @module ice/ice-agent
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Gather UDP host candidates, server-reflexive (srflx) candidates via STUN,
|
|
9
|
+
* and relay candidates via TURN (RFC 5766 ALLOCATE).
|
|
10
|
+
* - Send/answer STUN Binding connectivity checks carrying USERNAME,
|
|
11
|
+
* MESSAGE-INTEGRITY (keyed by the remote/local ice-pwd), PRIORITY, the
|
|
12
|
+
* ICE-CONTROLLING/CONTROLLED role attribute, and USE-CANDIDATE.
|
|
13
|
+
* - Nominate a candidate pair and expose it as the selected path.
|
|
14
|
+
* - Demultiplex inbound datagrams per RFC 7983: STUN (first byte 0-3) is
|
|
15
|
+
* handled internally; everything else (DTLS records, first byte 20-63) is
|
|
16
|
+
* emitted as 'data' for the upper stack.
|
|
17
|
+
*
|
|
18
|
+
* Each local candidate carries a `transport` with a uniform interface so the
|
|
19
|
+
* connectivity-check and data paths are identical whether the candidate is a
|
|
20
|
+
* host socket or a TURN relay:
|
|
21
|
+
* transport.send(buf, remoteAddress, remotePort)
|
|
22
|
+
* transport.onMessage = (buf, {address, port}) => ...
|
|
23
|
+
*/
|
|
24
|
+
import { EventEmitter } from 'events';
|
|
25
|
+
/** Remote info accompanying an inbound datagram. */
|
|
26
|
+
interface RemoteInfo {
|
|
27
|
+
address: string;
|
|
28
|
+
port: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Uniform transport abstraction shared by host sockets and TURN relays.
|
|
32
|
+
*/
|
|
33
|
+
interface Transport {
|
|
34
|
+
kind: string;
|
|
35
|
+
send(buf: Buffer, address: string, port: number): void;
|
|
36
|
+
onMessage: ((msg: Buffer, rinfo: RemoteInfo) => void) | null;
|
|
37
|
+
close(): void;
|
|
38
|
+
}
|
|
39
|
+
/** A local ICE candidate. */
|
|
40
|
+
interface LocalCandidate {
|
|
41
|
+
foundation: string;
|
|
42
|
+
component: number;
|
|
43
|
+
protocol: string;
|
|
44
|
+
priority: number;
|
|
45
|
+
address: string;
|
|
46
|
+
port: number;
|
|
47
|
+
type: string;
|
|
48
|
+
transport: Transport;
|
|
49
|
+
sdp: string;
|
|
50
|
+
}
|
|
51
|
+
/** A remote ICE candidate (parsed from an a=candidate line or object). */
|
|
52
|
+
interface RemoteCandidate {
|
|
53
|
+
address: string;
|
|
54
|
+
port: number;
|
|
55
|
+
priority?: number;
|
|
56
|
+
type?: string;
|
|
57
|
+
}
|
|
58
|
+
/** A candidate pair under connectivity checking. */
|
|
59
|
+
interface CandidatePair {
|
|
60
|
+
key?: string;
|
|
61
|
+
local: {
|
|
62
|
+
transport: Transport;
|
|
63
|
+
} & Partial<LocalCandidate>;
|
|
64
|
+
remote: {
|
|
65
|
+
address: string;
|
|
66
|
+
port: number;
|
|
67
|
+
} & Partial<RemoteCandidate>;
|
|
68
|
+
state?: string;
|
|
69
|
+
nominated?: boolean;
|
|
70
|
+
}
|
|
71
|
+
/** Description of a single ICE server entry. */
|
|
72
|
+
interface IceServer {
|
|
73
|
+
urls: string | string[];
|
|
74
|
+
username?: string;
|
|
75
|
+
credential?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Options accepted by {@link IceAgent#gather}. */
|
|
78
|
+
interface GatherOptions {
|
|
79
|
+
iceServers?: IceServer[];
|
|
80
|
+
iceTransportPolicy?: 'all' | 'relay';
|
|
81
|
+
}
|
|
82
|
+
/** Parsed query parameters from a STUN/TURN URL. */
|
|
83
|
+
type IceServerParams = Record<string, string | true>;
|
|
84
|
+
/** Result of {@link parseIceServerUrl}. */
|
|
85
|
+
interface ParsedIceServerUrl {
|
|
86
|
+
scheme: string;
|
|
87
|
+
protocol: string;
|
|
88
|
+
host: string;
|
|
89
|
+
port: number;
|
|
90
|
+
transport: string;
|
|
91
|
+
params: IceServerParams;
|
|
92
|
+
}
|
|
93
|
+
/** Options accepted by the {@link IceAgent} constructor. */
|
|
94
|
+
interface IceAgentOptions {
|
|
95
|
+
role: 'controlling' | 'controlled';
|
|
96
|
+
localUfrag: string;
|
|
97
|
+
localPwd: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Compute an ICE candidate priority (RFC 8445 §5.1.2.1).
|
|
101
|
+
*/
|
|
102
|
+
declare function candidatePriority(type: string, localPref?: number, componentId?: number): number;
|
|
103
|
+
/**
|
|
104
|
+
* Parse a STUN/TURN server URL: (stun|turn|turns):host[:port][?key=val&...].
|
|
105
|
+
* Query parameters are returned in `params`; a flag without a value (e.g.
|
|
106
|
+
* "?secure") is recorded as `true`, an empty value ("?transport=") as "".
|
|
107
|
+
* @param {string} url
|
|
108
|
+
* @returns {{scheme:string, protocol:string, host:string, port:number,
|
|
109
|
+
* transport:string, params:Object}|null} null if the URL is invalid.
|
|
110
|
+
*/
|
|
111
|
+
declare function parseIceServerUrl(url: string): ParsedIceServerUrl | null;
|
|
112
|
+
declare class IceAgent extends EventEmitter {
|
|
113
|
+
#private;
|
|
114
|
+
role: 'controlling' | 'controlled';
|
|
115
|
+
localUfrag: string;
|
|
116
|
+
localPwd: string;
|
|
117
|
+
remoteUfrag: string | null;
|
|
118
|
+
remotePwd: string | null;
|
|
119
|
+
/**
|
|
120
|
+
* @param {Object} opts
|
|
121
|
+
* @param {'controlling'|'controlled'} opts.role
|
|
122
|
+
* @param {string} opts.localUfrag
|
|
123
|
+
* @param {string} opts.localPwd
|
|
124
|
+
*/
|
|
125
|
+
constructor(opts: IceAgentOptions);
|
|
126
|
+
/**
|
|
127
|
+
* Gather candidates. Host candidates always; srflx/relay when iceServers are
|
|
128
|
+
* given. With iceTransportPolicy 'relay', only relay candidates are kept.
|
|
129
|
+
* @param {Object} [opts]
|
|
130
|
+
* @param {Array<{urls:string|string[],username?:string,credential?:string}>} [opts.iceServers]
|
|
131
|
+
* @param {'all'|'relay'} [opts.iceTransportPolicy='all']
|
|
132
|
+
*/
|
|
133
|
+
gather(opts?: GatherOptions): Promise<void>;
|
|
134
|
+
getLocalCandidates(): LocalCandidate[];
|
|
135
|
+
/** Set remote ICE credentials (from the peer's SDP). */
|
|
136
|
+
setRemoteCredentials(ufrag: string, pwd: string): void;
|
|
137
|
+
/**
|
|
138
|
+
* Add a remote candidate (parsed from an a=candidate line or object).
|
|
139
|
+
* @param {{address:string, port:number, priority?:number, type?:string}} cand
|
|
140
|
+
*/
|
|
141
|
+
addRemoteCandidate(cand: RemoteCandidate): void;
|
|
142
|
+
/** Begin connectivity checks (call once remote creds + candidates exist). */
|
|
143
|
+
start(): void;
|
|
144
|
+
/**
|
|
145
|
+
* Send application (DTLS) data over the selected path.
|
|
146
|
+
* @param {Buffer} data
|
|
147
|
+
*/
|
|
148
|
+
send(data: Buffer): void;
|
|
149
|
+
getSelectedPair(): CandidatePair | null;
|
|
150
|
+
/** Type of the selected local candidate ('host'|'srflx'|'relay'|'prflx'). */
|
|
151
|
+
getSelectedCandidateType(): string | null | undefined;
|
|
152
|
+
close(): void;
|
|
153
|
+
}
|
|
154
|
+
export { IceAgent, candidatePriority, parseIceServerUrl };
|