node-rtc-connection 2.0.4 → 2.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/index.cjs +1 -0
- package/index.mjs +1 -0
- package/package.json +10 -47
- package/{dist/types → types}/stun/stun-client.d.ts +2 -0
- package/dist/index.cjs +0 -32
- package/dist/index.mjs +0 -43
- package/src/crypto/der.ts +0 -205
- package/src/crypto/x509.ts +0 -146
- package/src/datachannel/RTCDataChannel.ts +0 -388
- package/src/dtls/RTCCertificate.ts +0 -396
- package/src/dtls/cipher.ts +0 -198
- package/src/dtls/connection.ts +0 -974
- package/src/dtls/prf.ts +0 -62
- package/src/dtls/protocol.ts +0 -204
- package/src/foundation/ByteBufferQueue.ts +0 -237
- package/src/foundation/RTCError.ts +0 -276
- package/src/ice/RTCIceCandidate.ts +0 -349
- package/src/ice/ice-agent.ts +0 -609
- package/src/ice/stun-message.ts +0 -260
- package/src/index.ts +0 -72
- package/src/peerconnection/RTCPeerConnection.ts +0 -430
- package/src/sctp/association.ts +0 -523
- package/src/sctp/chunks.ts +0 -350
- package/src/sctp/crc32c.ts +0 -57
- package/src/sctp/datachannel-manager.ts +0 -187
- package/src/sctp/dcep.ts +0 -94
- package/src/sdp/RTCSessionDescription.ts +0 -115
- package/src/sdp/sdp-utils.ts +0 -229
- package/src/stun/stun-client.ts +0 -936
- package/src/transport-stack.ts +0 -165
- /package/{dist/types → types}/crypto/der.d.ts +0 -0
- /package/{dist/types → types}/crypto/x509.d.ts +0 -0
- /package/{dist/types → types}/datachannel/RTCDataChannel.d.ts +0 -0
- /package/{dist/types → types}/dtls/RTCCertificate.d.ts +0 -0
- /package/{dist/types → types}/dtls/cipher.d.ts +0 -0
- /package/{dist/types → types}/dtls/connection.d.ts +0 -0
- /package/{dist/types → types}/dtls/prf.d.ts +0 -0
- /package/{dist/types → types}/dtls/protocol.d.ts +0 -0
- /package/{dist/types → types}/foundation/ByteBufferQueue.d.ts +0 -0
- /package/{dist/types → types}/foundation/RTCError.d.ts +0 -0
- /package/{dist/types → types}/ice/RTCIceCandidate.d.ts +0 -0
- /package/{dist/types → types}/ice/ice-agent.d.ts +0 -0
- /package/{dist/types → types}/ice/stun-message.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/peerconnection/RTCPeerConnection.d.ts +0 -0
- /package/{dist/types → types}/sctp/association.d.ts +0 -0
- /package/{dist/types → types}/sctp/chunks.d.ts +0 -0
- /package/{dist/types → types}/sctp/crc32c.d.ts +0 -0
- /package/{dist/types → types}/sctp/datachannel-manager.d.ts +0 -0
- /package/{dist/types → types}/sctp/dcep.d.ts +0 -0
- /package/{dist/types → types}/sdp/RTCSessionDescription.d.ts +0 -0
- /package/{dist/types → types}/sdp/sdp-utils.d.ts +0 -0
- /package/{dist/types → types}/transport-stack.d.ts +0 -0
|
@@ -1,276 +0,0 @@
|
|
|
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
|
-
'use strict';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* RTCErrorDetailType enum - Standardized WebRTC error details.
|
|
18
|
-
* Maps to RTCErrorDetailType from the WebRTC spec.
|
|
19
|
-
*
|
|
20
|
-
* @readonly
|
|
21
|
-
* @enum {string}
|
|
22
|
-
*/
|
|
23
|
-
const RTCErrorDetailType = Object.freeze({
|
|
24
|
-
NONE: 'none',
|
|
25
|
-
DATA_CHANNEL_FAILURE: 'data-channel-failure',
|
|
26
|
-
DTLS_FAILURE: 'dtls-failure',
|
|
27
|
-
FINGERPRINT_FAILURE: 'fingerprint-failure',
|
|
28
|
-
SCTP_FAILURE: 'sctp-failure',
|
|
29
|
-
SDP_SYNTAX_ERROR: 'sdp-syntax-error',
|
|
30
|
-
HARDWARE_ENCODER_NOT_AVAILABLE: 'hardware-encoder-not-available',
|
|
31
|
-
HARDWARE_ENCODER_ERROR: 'hardware-encoder-error',
|
|
32
|
-
INVALID_STATE: 'invalid-state',
|
|
33
|
-
INVALID_MODIFICATION: 'invalid-modification',
|
|
34
|
-
INVALID_ACCESS_ERROR: 'invalid-access-error',
|
|
35
|
-
OPERATION_ERROR: 'operation-error',
|
|
36
|
-
} as const);
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Error detail type string union.
|
|
40
|
-
*/
|
|
41
|
-
type RTCErrorDetail = typeof RTCErrorDetailType[keyof typeof RTCErrorDetailType];
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Error initialization dictionary.
|
|
45
|
-
*/
|
|
46
|
-
interface RTCErrorInit {
|
|
47
|
-
errorDetail?: string;
|
|
48
|
-
sdpLineNumber?: number | null;
|
|
49
|
-
httpRequestStatusCode?: number | null;
|
|
50
|
-
sctpCauseCode?: number | null;
|
|
51
|
-
receivedAlert?: number | null;
|
|
52
|
-
sentAlert?: number | null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Native WebRTC error object shape.
|
|
57
|
-
*/
|
|
58
|
-
interface NativeRTCError {
|
|
59
|
-
error_detail?: string;
|
|
60
|
-
sctp_cause_code?: number;
|
|
61
|
-
message?: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* JSON representation of an RTCError.
|
|
66
|
-
*/
|
|
67
|
-
interface RTCErrorJSON {
|
|
68
|
-
name: string;
|
|
69
|
-
message: string;
|
|
70
|
-
errorDetail: string;
|
|
71
|
-
sdpLineNumber?: number;
|
|
72
|
-
httpRequestStatusCode?: number;
|
|
73
|
-
sctpCauseCode?: number;
|
|
74
|
-
receivedAlert?: number;
|
|
75
|
-
sentAlert?: number;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* RTCError extends Error with WebRTC-specific error details.
|
|
80
|
-
*
|
|
81
|
-
* @extends Error
|
|
82
|
-
*/
|
|
83
|
-
class RTCError extends Error {
|
|
84
|
-
/** Export error detail types as static property */
|
|
85
|
-
static readonly DetailType = RTCErrorDetailType;
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Specific error category.
|
|
89
|
-
* @private {string}
|
|
90
|
-
*/
|
|
91
|
-
#errorDetail: string;
|
|
92
|
-
|
|
93
|
-
#sdpLineNumber: number | null;
|
|
94
|
-
#httpRequestStatusCode: number | null;
|
|
95
|
-
#sctpCauseCode: number | null;
|
|
96
|
-
#receivedAlert: number | null;
|
|
97
|
-
#sentAlert: number | null;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Creates a new RTCError.
|
|
101
|
-
*
|
|
102
|
-
* @param {RTCErrorInit} [init={}] - Error initialization dictionary
|
|
103
|
-
* @param {string} [init.errorDetail='none'] - Error detail type
|
|
104
|
-
* @param {number} [init.sdpLineNumber] - SDP line number where error occurred
|
|
105
|
-
* @param {number} [init.httpRequestStatusCode] - HTTP status code if relevant
|
|
106
|
-
* @param {number} [init.sctpCauseCode] - SCTP cause code
|
|
107
|
-
* @param {number} [init.receivedAlert] - TLS alert received
|
|
108
|
-
* @param {number} [init.sentAlert] - TLS alert sent
|
|
109
|
-
* @param {string} [message=''] - Error message
|
|
110
|
-
*/
|
|
111
|
-
constructor(init: RTCErrorInit = {}, message = '') {
|
|
112
|
-
super(message);
|
|
113
|
-
|
|
114
|
-
this.name = 'RTCError';
|
|
115
|
-
|
|
116
|
-
// Maintain stack trace in V8
|
|
117
|
-
if (Error.captureStackTrace) {
|
|
118
|
-
Error.captureStackTrace(this, RTCError);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Validate and set errorDetail
|
|
122
|
-
const errorDetail = init.errorDetail || RTCErrorDetailType.NONE;
|
|
123
|
-
if (typeof errorDetail !== 'string') {
|
|
124
|
-
throw new TypeError('errorDetail must be a string');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
this.#errorDetail = errorDetail;
|
|
128
|
-
|
|
129
|
-
// Optional numeric fields with validation
|
|
130
|
-
this.#sdpLineNumber = this.#validateInteger(init.sdpLineNumber, 'sdpLineNumber');
|
|
131
|
-
this.#httpRequestStatusCode = this.#validateInteger(init.httpRequestStatusCode, 'httpRequestStatusCode');
|
|
132
|
-
this.#sctpCauseCode = this.#validateInteger(init.sctpCauseCode, 'sctpCauseCode');
|
|
133
|
-
this.#receivedAlert = this.#validateUnsignedInteger(init.receivedAlert, 'receivedAlert');
|
|
134
|
-
this.#sentAlert = this.#validateUnsignedInteger(init.sentAlert, 'sentAlert');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Validates that a value is an integer or null/undefined.
|
|
139
|
-
* @private
|
|
140
|
-
* @param {*} value - Value to validate
|
|
141
|
-
* @param {string} fieldName - Field name for error messages
|
|
142
|
-
* @returns {number|null}
|
|
143
|
-
* @throws {TypeError} If value is not an integer
|
|
144
|
-
*/
|
|
145
|
-
#validateInteger(value: number | null | undefined, fieldName: string): number | null {
|
|
146
|
-
if (value === undefined || value === null) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
const num = Number(value);
|
|
150
|
-
if (!Number.isInteger(num)) {
|
|
151
|
-
throw new TypeError(`${fieldName} must be an integer`);
|
|
152
|
-
}
|
|
153
|
-
return num;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Validates that a value is an unsigned integer or null/undefined.
|
|
158
|
-
* @private
|
|
159
|
-
* @param {*} value - Value to validate
|
|
160
|
-
* @param {string} fieldName - Field name for error messages
|
|
161
|
-
* @returns {number|null}
|
|
162
|
-
* @throws {TypeError} If value is not an unsigned integer
|
|
163
|
-
*/
|
|
164
|
-
#validateUnsignedInteger(value: number | null | undefined, fieldName: string): number | null {
|
|
165
|
-
if (value === undefined || value === null) {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
const num = Number(value);
|
|
169
|
-
if (!Number.isInteger(num) || num < 0) {
|
|
170
|
-
throw new TypeError(`${fieldName} must be an unsigned integer`);
|
|
171
|
-
}
|
|
172
|
-
return num;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* RTCErrorDetailType - specific error category.
|
|
177
|
-
* @type {string}
|
|
178
|
-
*/
|
|
179
|
-
get errorDetail(): string {
|
|
180
|
-
return this.#errorDetail;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* SDP line number where the error occurred (if applicable).
|
|
185
|
-
* @type {number|null}
|
|
186
|
-
*/
|
|
187
|
-
get sdpLineNumber(): number | null {
|
|
188
|
-
return this.#sdpLineNumber;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* HTTP request status code (if applicable).
|
|
193
|
-
* @type {number|null}
|
|
194
|
-
*/
|
|
195
|
-
get httpRequestStatusCode(): number | null {
|
|
196
|
-
return this.#httpRequestStatusCode;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* SCTP cause code (if applicable).
|
|
201
|
-
* @type {number|null}
|
|
202
|
-
*/
|
|
203
|
-
get sctpCauseCode(): number | null {
|
|
204
|
-
return this.#sctpCauseCode;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* TLS alert value received (if applicable).
|
|
209
|
-
* @type {number|null}
|
|
210
|
-
*/
|
|
211
|
-
get receivedAlert(): number | null {
|
|
212
|
-
return this.#receivedAlert;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* TLS alert value sent (if applicable).
|
|
217
|
-
* @type {number|null}
|
|
218
|
-
*/
|
|
219
|
-
get sentAlert(): number | null {
|
|
220
|
-
return this.#sentAlert;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Converts error to JSON representation.
|
|
225
|
-
* @returns {Object} JSON representation of the error
|
|
226
|
-
*/
|
|
227
|
-
toJSON(): RTCErrorJSON {
|
|
228
|
-
const json: RTCErrorJSON = {
|
|
229
|
-
name: this.name,
|
|
230
|
-
message: this.message,
|
|
231
|
-
errorDetail: this.#errorDetail,
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (this.#sdpLineNumber !== null) {
|
|
235
|
-
json.sdpLineNumber = this.#sdpLineNumber;
|
|
236
|
-
}
|
|
237
|
-
if (this.#httpRequestStatusCode !== null) {
|
|
238
|
-
json.httpRequestStatusCode = this.#httpRequestStatusCode;
|
|
239
|
-
}
|
|
240
|
-
if (this.#sctpCauseCode !== null) {
|
|
241
|
-
json.sctpCauseCode = this.#sctpCauseCode;
|
|
242
|
-
}
|
|
243
|
-
if (this.#receivedAlert !== null) {
|
|
244
|
-
json.receivedAlert = this.#receivedAlert;
|
|
245
|
-
}
|
|
246
|
-
if (this.#sentAlert !== null) {
|
|
247
|
-
json.sentAlert = this.#sentAlert;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return json;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Creates RTCError from a native WebRTC error object.
|
|
255
|
-
* @param {Object} nativeError - Native error object
|
|
256
|
-
* @param {string} [nativeError.error_detail] - Error detail type
|
|
257
|
-
* @param {number} [nativeError.sctp_cause_code] - SCTP cause code
|
|
258
|
-
* @param {string} [nativeError.message] - Error message
|
|
259
|
-
* @returns {RTCError}
|
|
260
|
-
*/
|
|
261
|
-
static fromNative(nativeError: NativeRTCError): RTCError {
|
|
262
|
-
const init: RTCErrorInit = {
|
|
263
|
-
errorDetail: nativeError.error_detail || RTCErrorDetailType.NONE,
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
if (nativeError.sctp_cause_code !== undefined) {
|
|
267
|
-
init.sctpCauseCode = nativeError.sctp_cause_code;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return new RTCError(init, nativeError.message || 'Unknown error');
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export default RTCError;
|
|
275
|
-
export { RTCError, RTCErrorDetailType };
|
|
276
|
-
export type { RTCErrorInit, RTCErrorDetail, NativeRTCError, RTCErrorJSON };
|
|
@@ -1,349 +0,0 @@
|
|
|
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
|
-
'use strict';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Initialization dictionary for RTCIceCandidate.
|
|
18
|
-
*/
|
|
19
|
-
interface RTCIceCandidateInit {
|
|
20
|
-
candidate?: string;
|
|
21
|
-
sdpMid?: string | null;
|
|
22
|
-
sdpMLineIndex?: number | null;
|
|
23
|
-
usernameFragment?: string | null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Parsed attributes extracted from an ICE candidate string.
|
|
28
|
-
*/
|
|
29
|
-
interface ParsedCandidateAttributes {
|
|
30
|
-
foundation: string | null;
|
|
31
|
-
component: string | null;
|
|
32
|
-
protocol: string | null;
|
|
33
|
-
priority: number | null;
|
|
34
|
-
address: string | null;
|
|
35
|
-
port: number | null;
|
|
36
|
-
type: string | null;
|
|
37
|
-
tcpType: string | null;
|
|
38
|
-
relatedAddress: string | null;
|
|
39
|
-
relatedPort: number | null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* JSON representation of an RTCIceCandidate.
|
|
44
|
-
*/
|
|
45
|
-
interface RTCIceCandidateJSON {
|
|
46
|
-
candidate: string;
|
|
47
|
-
sdpMid: string | null;
|
|
48
|
-
sdpMLineIndex: number | null;
|
|
49
|
-
usernameFragment?: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* RTCIceCandidate represents a potential method for establishing connectivity.
|
|
54
|
-
*
|
|
55
|
-
* ICE candidates are described using SDP (Session Description Protocol) syntax.
|
|
56
|
-
* Each candidate describes a single address/port combination and transport protocol.
|
|
57
|
-
*/
|
|
58
|
-
class RTCIceCandidate {
|
|
59
|
-
/**
|
|
60
|
-
* SDP candidate string.
|
|
61
|
-
* @private {string}
|
|
62
|
-
*/
|
|
63
|
-
#candidate: string;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Media stream identification.
|
|
67
|
-
* @private {string|null}
|
|
68
|
-
*/
|
|
69
|
-
#sdpMid: string | null;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Media line index (zero-based).
|
|
73
|
-
* @private {number|null}
|
|
74
|
-
*/
|
|
75
|
-
#sdpMLineIndex: number | null;
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* ICE username fragment.
|
|
79
|
-
* @private {string|null}
|
|
80
|
-
*/
|
|
81
|
-
#usernameFragment: string | null;
|
|
82
|
-
|
|
83
|
-
#parsedAttributes: ParsedCandidateAttributes;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Creates a new RTCIceCandidate.
|
|
87
|
-
*
|
|
88
|
-
* @param {RTCIceCandidateInit} [candidateInit={}] - Initialization dictionary
|
|
89
|
-
* @param {string} [candidateInit.candidate=''] - SDP candidate string
|
|
90
|
-
* @param {string|null} [candidateInit.sdpMid] - Media stream ID
|
|
91
|
-
* @param {number|null} [candidateInit.sdpMLineIndex] - M-line index
|
|
92
|
-
* @param {string} [candidateInit.usernameFragment] - ICE username fragment
|
|
93
|
-
* @throws {TypeError} If both sdpMid and sdpMLineIndex are null
|
|
94
|
-
*/
|
|
95
|
-
constructor(candidateInit: RTCIceCandidateInit = {}) {
|
|
96
|
-
// Validate that at least one of sdpMid or sdpMLineIndex is present
|
|
97
|
-
if (candidateInit.sdpMid === null && candidateInit.sdpMLineIndex === null) {
|
|
98
|
-
throw new TypeError('sdpMid and sdpMLineIndex are both null');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
this.#candidate = candidateInit.candidate || '';
|
|
102
|
-
|
|
103
|
-
this.#sdpMid = candidateInit.sdpMid !== undefined ? candidateInit.sdpMid : null;
|
|
104
|
-
|
|
105
|
-
this.#sdpMLineIndex = candidateInit.sdpMLineIndex !== undefined ?
|
|
106
|
-
candidateInit.sdpMLineIndex : null;
|
|
107
|
-
|
|
108
|
-
this.#usernameFragment = candidateInit.usernameFragment || null;
|
|
109
|
-
|
|
110
|
-
// Parse candidate string for detailed attributes
|
|
111
|
-
this.#parsedAttributes = this.#parseCandidate(this.#candidate);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Parses an ICE candidate string to extract attributes.
|
|
116
|
-
* Format: "candidate:foundation component protocol priority address port typ type [raddr reladdr] [rport relport]"
|
|
117
|
-
*
|
|
118
|
-
* @private
|
|
119
|
-
* @param {string} candidateStr - Candidate string to parse
|
|
120
|
-
* @returns {Object} Parsed attributes
|
|
121
|
-
*/
|
|
122
|
-
#parseCandidate(candidateStr: string): ParsedCandidateAttributes {
|
|
123
|
-
const attrs: ParsedCandidateAttributes = {
|
|
124
|
-
foundation: null,
|
|
125
|
-
component: null,
|
|
126
|
-
protocol: null,
|
|
127
|
-
priority: null,
|
|
128
|
-
address: null,
|
|
129
|
-
port: null,
|
|
130
|
-
type: null,
|
|
131
|
-
tcpType: null,
|
|
132
|
-
relatedAddress: null,
|
|
133
|
-
relatedPort: null,
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
if (!candidateStr || !candidateStr.startsWith('candidate:')) {
|
|
137
|
-
return attrs;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Remove "candidate:" prefix
|
|
141
|
-
const parts = candidateStr.substring(10).trim().split(/\s+/);
|
|
142
|
-
|
|
143
|
-
if (parts.length < 8) {
|
|
144
|
-
return attrs;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Parse fixed fields
|
|
148
|
-
attrs.foundation = parts[0]!;
|
|
149
|
-
attrs.component = parts[1]!;
|
|
150
|
-
attrs.protocol = parts[2]!.toLowerCase();
|
|
151
|
-
attrs.priority = parseInt(parts[3]!, 10);
|
|
152
|
-
attrs.address = parts[4]!;
|
|
153
|
-
attrs.port = parseInt(parts[5]!, 10);
|
|
154
|
-
|
|
155
|
-
// parts[6] should be "typ"
|
|
156
|
-
if (parts[6] === 'typ') {
|
|
157
|
-
attrs.type = parts[7]!;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Parse optional attributes
|
|
161
|
-
for (let i = 8; i < parts.length; i += 2) {
|
|
162
|
-
const key = parts[i];
|
|
163
|
-
const value = parts[i + 1];
|
|
164
|
-
|
|
165
|
-
if (key === 'raddr') {
|
|
166
|
-
attrs.relatedAddress = value!;
|
|
167
|
-
} else if (key === 'rport') {
|
|
168
|
-
attrs.relatedPort = parseInt(value!, 10);
|
|
169
|
-
} else if (key === 'tcptype') {
|
|
170
|
-
attrs.tcpType = value!;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return attrs;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* SDP candidate attribute containing the candidate description.
|
|
179
|
-
* @type {string}
|
|
180
|
-
*/
|
|
181
|
-
get candidate(): string {
|
|
182
|
-
return this.#candidate;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Media stream identification tag.
|
|
187
|
-
* @type {string|null}
|
|
188
|
-
*/
|
|
189
|
-
get sdpMid(): string | null {
|
|
190
|
-
return this.#sdpMid;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Index of the m-line in the SDP this candidate is associated with.
|
|
195
|
-
* @type {number|null}
|
|
196
|
-
*/
|
|
197
|
-
get sdpMLineIndex(): number | null {
|
|
198
|
-
return this.#sdpMLineIndex;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* ICE username fragment.
|
|
203
|
-
* @type {string|null}
|
|
204
|
-
*/
|
|
205
|
-
get usernameFragment(): string | null {
|
|
206
|
-
return this.#usernameFragment;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Unique identifier for this candidate.
|
|
211
|
-
* @type {string|null}
|
|
212
|
-
*/
|
|
213
|
-
get foundation(): string | null {
|
|
214
|
-
return this.#parsedAttributes.foundation;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Component identifier (rtp=1, rtcp=2).
|
|
219
|
-
* @type {string|null}
|
|
220
|
-
*/
|
|
221
|
-
get component(): string | null {
|
|
222
|
-
return this.#parsedAttributes.component;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Priority value for this candidate.
|
|
227
|
-
* Higher priority candidates are preferred.
|
|
228
|
-
* @type {number|null}
|
|
229
|
-
*/
|
|
230
|
-
get priority(): number | null {
|
|
231
|
-
return this.#parsedAttributes.priority;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* IP address of this candidate.
|
|
236
|
-
* @type {string|null}
|
|
237
|
-
*/
|
|
238
|
-
get address(): string | null {
|
|
239
|
-
return this.#parsedAttributes.address;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Transport protocol (udp/tcp).
|
|
244
|
-
* @type {string|null}
|
|
245
|
-
*/
|
|
246
|
-
get protocol(): string | null {
|
|
247
|
-
return this.#parsedAttributes.protocol;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Port number.
|
|
252
|
-
* @type {number|null}
|
|
253
|
-
*/
|
|
254
|
-
get port(): number | null {
|
|
255
|
-
return this.#parsedAttributes.port;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Type of candidate (host, srflx, prflx, relay).
|
|
260
|
-
* @type {string|null}
|
|
261
|
-
*/
|
|
262
|
-
get type(): string | null {
|
|
263
|
-
return this.#parsedAttributes.type;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* TCP candidate type (active, passive, so).
|
|
268
|
-
* Only applicable for TCP candidates.
|
|
269
|
-
* @type {string|null}
|
|
270
|
-
*/
|
|
271
|
-
get tcpType(): string | null {
|
|
272
|
-
return this.#parsedAttributes.tcpType;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Related address for reflexive/relay candidates.
|
|
277
|
-
* @type {string|null}
|
|
278
|
-
*/
|
|
279
|
-
get relatedAddress(): string | null {
|
|
280
|
-
return this.#parsedAttributes.relatedAddress;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Related port for reflexive/relay candidates.
|
|
285
|
-
* @type {number|null}
|
|
286
|
-
*/
|
|
287
|
-
get relatedPort(): number | null {
|
|
288
|
-
return this.#parsedAttributes.relatedPort;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Converts candidate to JSON representation.
|
|
293
|
-
* @returns {Object} JSON representation
|
|
294
|
-
*/
|
|
295
|
-
toJSON(): RTCIceCandidateJSON {
|
|
296
|
-
const json: RTCIceCandidateJSON = {
|
|
297
|
-
candidate: this.#candidate,
|
|
298
|
-
sdpMid: this.#sdpMid,
|
|
299
|
-
sdpMLineIndex: this.#sdpMLineIndex,
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
if (this.#usernameFragment) {
|
|
303
|
-
json.usernameFragment = this.#usernameFragment;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return json;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* Creates an RTCIceCandidate from a candidate string.
|
|
311
|
-
*
|
|
312
|
-
* @param {string} candidateStr - ICE candidate string
|
|
313
|
-
* @param {string|null} [sdpMid=null] - Media stream ID
|
|
314
|
-
* @param {number|null} [sdpMLineIndex=0] - M-line index
|
|
315
|
-
* @returns {RTCIceCandidate}
|
|
316
|
-
*/
|
|
317
|
-
static fromString(candidateStr: string, sdpMid: string | null = null, sdpMLineIndex: number | null = 0): RTCIceCandidate {
|
|
318
|
-
return new RTCIceCandidate({
|
|
319
|
-
candidate: candidateStr,
|
|
320
|
-
sdpMid,
|
|
321
|
-
sdpMLineIndex,
|
|
322
|
-
});
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Validates if a string is a valid candidate format.
|
|
327
|
-
*
|
|
328
|
-
* @param {string} candidateStr - String to validate
|
|
329
|
-
* @returns {boolean} True if valid candidate format
|
|
330
|
-
*/
|
|
331
|
-
static isValid(candidateStr: string): boolean {
|
|
332
|
-
if (!candidateStr || typeof candidateStr !== 'string') {
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Must start with "candidate:"
|
|
337
|
-
if (!candidateStr.startsWith('candidate:')) {
|
|
338
|
-
return false;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Must have at least the minimum required fields
|
|
342
|
-
const parts = candidateStr.substring(10).trim().split(/\s+/);
|
|
343
|
-
return parts.length >= 8;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
export default RTCIceCandidate;
|
|
348
|
-
export { RTCIceCandidate };
|
|
349
|
-
export type { RTCIceCandidateInit, ParsedCandidateAttributes, RTCIceCandidateJSON };
|