werift 0.14.5 → 0.15.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/lib/common/src/binary.d.ts +0 -1
- package/lib/common/src/binary.js +1 -2
- package/lib/common/src/binary.js.map +1 -1
- package/lib/dtls/src/context/cipher.js +5 -2
- package/lib/dtls/src/context/cipher.js.map +1 -1
- package/lib/dtls/src/handshake/extensions/useSrtp.js +5 -2
- package/lib/dtls/src/handshake/extensions/useSrtp.js.map +1 -1
- package/lib/ice/src/candidate.js +5 -2
- package/lib/ice/src/candidate.js.map +1 -1
- package/lib/ice/src/ice.d.ts +2 -2
- package/lib/ice/src/ice.js +19 -8
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/stun/attributes.js +5 -2
- package/lib/ice/src/stun/attributes.js.map +1 -1
- package/lib/rtp/src/rtcp/rr.js +5 -2
- package/lib/rtp/src/rtcp/rr.js.map +1 -1
- package/lib/rtp/src/rtcp/rtpfb/nack.js +6 -3
- package/lib/rtp/src/rtcp/rtpfb/nack.js.map +1 -1
- package/lib/rtp/src/rtcp/rtpfb/twcc.js +6 -6
- package/lib/rtp/src/rtcp/rtpfb/twcc.js.map +1 -1
- package/lib/rtp/src/rtcp/sr.js +5 -2
- package/lib/rtp/src/rtcp/sr.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/ctr.js +5 -2
- package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/gcm.js +6 -3
- package/lib/rtp/src/srtp/cipher/gcm.js.map +1 -1
- package/lib/sctp/src/param.js +5 -2
- package/lib/sctp/src/param.js.map +1 -1
- package/lib/sctp/src/sctp.js +5 -5
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/dataChannel.js +3 -2
- package/lib/webrtc/src/dataChannel.js.map +1 -1
- package/lib/webrtc/src/media/receiver/nack.js +2 -2
- package/lib/webrtc/src/media/receiver/nack.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +3 -2
- package/lib/webrtc/src/media/rtpReceiver.js +4 -2
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.d.ts +4 -2
- package/lib/webrtc/src/media/rtpSender.js +15 -7
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/media/rtpTransceiver.d.ts +7 -6
- package/lib/webrtc/src/media/rtpTransceiver.js +10 -3
- package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +10 -10
- package/lib/webrtc/src/peerConnection.js +356 -211
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/sdp.js +5 -2
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.d.ts +3 -2
- package/lib/webrtc/src/transport/dtls.js +3 -0
- package/lib/webrtc/src/transport/dtls.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.d.ts +5 -3
- package/lib/webrtc/src/transport/sctp.js +46 -34
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/package.json +2 -2
- package/src/dataChannel.ts +4 -2
- package/src/media/receiver/nack.ts +1 -1
- package/src/media/rtpReceiver.ts +6 -5
- package/src/media/rtpSender.ts +18 -9
- package/src/media/rtpTransceiver.ts +17 -6
- package/src/peerConnection.ts +431 -253
- package/src/sdp.ts +1 -1
- package/src/transport/dtls.ts +4 -1
- package/src/transport/sctp.ts +53 -33
|
@@ -24,7 +24,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.defaultPeerConfig = exports.findCodecByMimeType = exports.allocateMid = exports.addTransportDescription = exports.createMediaDescriptionForSctp = exports.createMediaDescriptionForTransceiver = exports.RTCPeerConnection = void 0;
|
|
26
26
|
const debug_1 = __importDefault(require("debug"));
|
|
27
|
-
const
|
|
27
|
+
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
|
|
28
|
+
const isEqual_1 = __importDefault(require("lodash/isEqual"));
|
|
28
29
|
const rx_mini_1 = __importDefault(require("rx.mini"));
|
|
29
30
|
const uuid = __importStar(require("uuid"));
|
|
30
31
|
const _1 = require(".");
|
|
@@ -44,11 +45,11 @@ const sctp_1 = require("./transport/sctp");
|
|
|
44
45
|
const utils_1 = require("./utils");
|
|
45
46
|
const log = (0, debug_1.default)("werift:packages/webrtc/src/peerConnection.ts");
|
|
46
47
|
class RTCPeerConnection extends helper_1.EventTarget {
|
|
47
|
-
constructor({ codecs, headerExtensions, iceServers, iceTransportPolicy, icePortRange, dtls, } = {}) {
|
|
48
|
+
constructor({ codecs, headerExtensions, iceServers, iceTransportPolicy, icePortRange, dtls, bundlePolicy, } = {}) {
|
|
48
49
|
super();
|
|
49
50
|
this.cname = uuid.v4();
|
|
50
51
|
this.masterTransportEstablished = false;
|
|
51
|
-
this.configuration = (0,
|
|
52
|
+
this.configuration = (0, cloneDeep_1.default)(exports.defaultPeerConfig);
|
|
52
53
|
this.connectionState = "new";
|
|
53
54
|
this.iceConnectionState = "new";
|
|
54
55
|
this.iceGatheringState = "new";
|
|
@@ -61,11 +62,6 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
61
62
|
this.connectionStateChange = new rx_mini_1.default();
|
|
62
63
|
this.onDataChannel = new rx_mini_1.default();
|
|
63
64
|
this.onRemoteTransceiverAdded = new rx_mini_1.default();
|
|
64
|
-
/**
|
|
65
|
-
* should use onRemoteTransceiverAdded
|
|
66
|
-
* @deprecated
|
|
67
|
-
*/
|
|
68
|
-
this.onTransceiver = new rx_mini_1.default();
|
|
69
65
|
this.onTransceiverAdded = new rx_mini_1.default();
|
|
70
66
|
this.onIceCandidate = new rx_mini_1.default();
|
|
71
67
|
this.onNegotiationneeded = new rx_mini_1.default();
|
|
@@ -148,12 +144,24 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
148
144
|
break;
|
|
149
145
|
}
|
|
150
146
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.
|
|
147
|
+
if (bundlePolicy) {
|
|
148
|
+
this.configuration.bundlePolicy = bundlePolicy;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
get dtlsTransports() {
|
|
152
|
+
const transports = this.transceivers.map((t) => t.dtlsTransport);
|
|
153
|
+
if (this.sctpTransport) {
|
|
154
|
+
transports.push(this.sctpTransport.dtlsTransport);
|
|
155
|
+
}
|
|
156
|
+
return transports.reduce((acc, cur) => {
|
|
157
|
+
if (!acc.map((d) => d.id).includes(cur.id)) {
|
|
158
|
+
acc.push(cur);
|
|
159
|
+
}
|
|
160
|
+
return acc;
|
|
161
|
+
}, []);
|
|
162
|
+
}
|
|
163
|
+
get iceTransports() {
|
|
164
|
+
return this.dtlsTransports.map((d) => d.iceTransport);
|
|
157
165
|
}
|
|
158
166
|
get localDescription() {
|
|
159
167
|
if (!this._localDescription)
|
|
@@ -178,9 +186,7 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
178
186
|
return this.transceivers.find((transceiver) => transceiver.mLineIndex === index);
|
|
179
187
|
}
|
|
180
188
|
async createOffer() {
|
|
181
|
-
|
|
182
|
-
await this.dtlsTransport.setupCertificate();
|
|
183
|
-
}
|
|
189
|
+
await this.ensureCerts();
|
|
184
190
|
this.transceivers.forEach((transceiver) => {
|
|
185
191
|
transceiver.codecs = this.configuration.codecs[transceiver.kind];
|
|
186
192
|
transceiver.headerExtensions =
|
|
@@ -222,11 +228,13 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
222
228
|
!description.media.find((m) => this.sctpTransport.mid === m.rtp.muxId)) {
|
|
223
229
|
description.media.push(createMediaDescriptionForSctp(this.sctpTransport, allocateMid(this.seenMid)));
|
|
224
230
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
231
|
+
if (this.configuration.bundlePolicy !== "disable") {
|
|
232
|
+
const mids = description.media
|
|
233
|
+
.map((m) => m.rtp.muxId)
|
|
234
|
+
.filter((v) => v);
|
|
235
|
+
const bundle = new sdp_1.GroupDescription("BUNDLE", mids);
|
|
236
|
+
description.group.push(bundle);
|
|
237
|
+
}
|
|
230
238
|
return description.toJSON();
|
|
231
239
|
}
|
|
232
240
|
createDataChannel(label, options = {}) {
|
|
@@ -252,7 +260,8 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
252
260
|
ordered: settings.ordered,
|
|
253
261
|
protocol: settings.protocol,
|
|
254
262
|
});
|
|
255
|
-
|
|
263
|
+
const channel = new dataChannel_1.RTCDataChannel(this.sctpTransport, parameters);
|
|
264
|
+
return channel;
|
|
256
265
|
}
|
|
257
266
|
removeTrack(sender) {
|
|
258
267
|
if (this.isClosed)
|
|
@@ -277,20 +286,31 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
277
286
|
this.needNegotiation();
|
|
278
287
|
}
|
|
279
288
|
createTransport(srtpProfiles = []) {
|
|
289
|
+
const [existing] = this.iceTransports;
|
|
290
|
+
// Gather ICE candidates for only one track. If the remote endpoint is not bundle-aware, negotiate only one media track.
|
|
291
|
+
// https://w3c.github.io/webrtc-pc/#rtcbundlepolicy-enum
|
|
292
|
+
if (this.configuration.bundlePolicy === "max-bundle") {
|
|
293
|
+
if (existing) {
|
|
294
|
+
return this.dtlsTransports[0];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
280
297
|
const iceGatherer = new ice_1.RTCIceGatherer({
|
|
281
298
|
...(0, utils_1.parseIceServers)(this.configuration.iceServers),
|
|
282
299
|
forceTurn: this.configuration.iceTransportPolicy === "relay",
|
|
283
300
|
portRange: this.configuration.icePortRange,
|
|
284
301
|
});
|
|
285
|
-
|
|
286
|
-
|
|
302
|
+
if (existing) {
|
|
303
|
+
iceGatherer.connection.localUserName = existing.connection.localUserName;
|
|
304
|
+
iceGatherer.connection.localPassword = existing.connection.localPassword;
|
|
305
|
+
}
|
|
306
|
+
iceGatherer.onGatheringStateChange.subscribe(() => {
|
|
307
|
+
this.updateIceGatheringState();
|
|
287
308
|
});
|
|
288
|
-
this.updateIceGatheringState(
|
|
309
|
+
this.updateIceGatheringState();
|
|
289
310
|
const iceTransport = new ice_1.RTCIceTransport(iceGatherer);
|
|
290
|
-
iceTransport.onStateChange.subscribe((
|
|
291
|
-
this.updateIceConnectionState(
|
|
311
|
+
iceTransport.onStateChange.subscribe(() => {
|
|
312
|
+
this.updateIceConnectionState();
|
|
292
313
|
});
|
|
293
|
-
this.updateIceConnectionState(iceTransport.state);
|
|
294
314
|
iceTransport.iceGather.onIceCandidate = (candidate) => {
|
|
295
315
|
if (!this.localDescription)
|
|
296
316
|
return;
|
|
@@ -302,7 +322,6 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
302
322
|
}
|
|
303
323
|
candidate.sdpMLineIndex = 0;
|
|
304
324
|
candidate.sdpMid = media.rtp.muxId;
|
|
305
|
-
// for chrome & firefox & maybe others
|
|
306
325
|
candidate.foundation = "candidate:" + candidate.foundation;
|
|
307
326
|
this.onIceCandidate.execute(candidate.toJSON());
|
|
308
327
|
if (this.onicecandidate)
|
|
@@ -310,10 +329,15 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
310
329
|
this.emit("icecandidate", { candidate });
|
|
311
330
|
};
|
|
312
331
|
const dtlsTransport = new dtls_1.RTCDtlsTransport(iceTransport, this.router, this.certificates, srtpProfiles);
|
|
313
|
-
return
|
|
332
|
+
return dtlsTransport;
|
|
314
333
|
}
|
|
315
334
|
createSctpTransport() {
|
|
316
|
-
const
|
|
335
|
+
const dtlsTransport = this.createTransport([
|
|
336
|
+
const_1.SRTP_PROFILE.SRTP_AEAD_AES_128_GCM,
|
|
337
|
+
const_1.SRTP_PROFILE.SRTP_AES128_CM_HMAC_SHA1_80,
|
|
338
|
+
]);
|
|
339
|
+
const sctp = new sctp_1.RTCSctpTransport();
|
|
340
|
+
sctp.setDtlsTransport(dtlsTransport);
|
|
317
341
|
sctp.mid = undefined;
|
|
318
342
|
sctp.onDataChannel.subscribe((channel) => {
|
|
319
343
|
this.onDataChannel.execute(channel);
|
|
@@ -322,6 +346,8 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
322
346
|
this.ondatachannel(event);
|
|
323
347
|
this.emit("datachannel", event);
|
|
324
348
|
});
|
|
349
|
+
this.sctpTransport = sctp;
|
|
350
|
+
this.updateIceConnectionState();
|
|
325
351
|
return sctp;
|
|
326
352
|
}
|
|
327
353
|
async setLocalDescription(sessionDescription) {
|
|
@@ -339,9 +365,6 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
339
365
|
// # assign MID
|
|
340
366
|
description.media.forEach((media, i) => {
|
|
341
367
|
const mid = media.rtp.muxId;
|
|
342
|
-
if (!mid) {
|
|
343
|
-
throw new Error("mid not exist");
|
|
344
|
-
}
|
|
345
368
|
this.seenMid.add(mid);
|
|
346
369
|
if (["audio", "video"].includes(media.kind)) {
|
|
347
370
|
const transceiver = this.getTransceiverByMLineIndex(i);
|
|
@@ -353,26 +376,30 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
353
376
|
this.sctpTransport.mid = mid;
|
|
354
377
|
}
|
|
355
378
|
});
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
this.iceTransport.connection.iceControlling = false;
|
|
362
|
-
}
|
|
363
|
-
// One agent full, one lite: The full agent MUST take the controlling role, and the lite agent MUST take the controlled role
|
|
364
|
-
// RFC 8445 S6.1.1
|
|
365
|
-
if (this.iceTransport.connection.remoteIsLite) {
|
|
366
|
-
this.iceTransport.connection.iceControlling = true;
|
|
367
|
-
}
|
|
368
|
-
// # set DTLS role for mediasoup
|
|
369
|
-
if (description.type === "answer") {
|
|
370
|
-
const role = description.media.find((media) => media.dtlsParams)
|
|
371
|
-
?.dtlsParams?.role;
|
|
372
|
-
if (role) {
|
|
373
|
-
this.dtlsTransport.role = role;
|
|
379
|
+
const setupRole = (dtlsTransport) => {
|
|
380
|
+
const iceTransport = dtlsTransport.iceTransport;
|
|
381
|
+
// # set ICE role
|
|
382
|
+
if (description.type === "offer") {
|
|
383
|
+
iceTransport.connection.iceControlling = true;
|
|
374
384
|
}
|
|
375
|
-
|
|
385
|
+
else {
|
|
386
|
+
iceTransport.connection.iceControlling = false;
|
|
387
|
+
}
|
|
388
|
+
// One agent full, one lite: The full agent MUST take the controlling role, and the lite agent MUST take the controlled role
|
|
389
|
+
// RFC 8445 S6.1.1
|
|
390
|
+
if (iceTransport.connection.remoteIsLite) {
|
|
391
|
+
iceTransport.connection.iceControlling = true;
|
|
392
|
+
}
|
|
393
|
+
// # set DTLS role for mediasoup
|
|
394
|
+
if (description.type === "answer") {
|
|
395
|
+
const role = description.media.find((media) => media.dtlsParams)
|
|
396
|
+
?.dtlsParams?.role;
|
|
397
|
+
if (role) {
|
|
398
|
+
dtlsTransport.role = role;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
this.dtlsTransports.forEach((d) => setupRole(d));
|
|
376
403
|
// # configure direction
|
|
377
404
|
this.transceivers.forEach((t) => {
|
|
378
405
|
if (["answer", "pranswer"].includes(description.type)) {
|
|
@@ -383,10 +410,18 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
383
410
|
// for trickle ice
|
|
384
411
|
this.setLocal(description);
|
|
385
412
|
// # gather candidates
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
413
|
+
for (const iceTransport of this.iceTransports) {
|
|
414
|
+
await iceTransport.iceGather.gather();
|
|
415
|
+
}
|
|
416
|
+
description.media
|
|
417
|
+
.filter((m) => ["audio", "video"].includes(m.kind))
|
|
418
|
+
.forEach((m, i) => {
|
|
419
|
+
addTransportDescription(m, this.transceivers[i].dtlsTransport);
|
|
389
420
|
});
|
|
421
|
+
const sctpMedia = description.media.find((m) => m.kind === "application");
|
|
422
|
+
if (this.sctpTransport && sctpMedia) {
|
|
423
|
+
addTransportDescription(sctpMedia, this.sctpTransport.dtlsTransport);
|
|
424
|
+
}
|
|
390
425
|
this.setLocal(description);
|
|
391
426
|
// connect transports
|
|
392
427
|
if (description.type === "answer") {
|
|
@@ -412,33 +447,36 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
412
447
|
}
|
|
413
448
|
async addIceCandidate(candidateMessage) {
|
|
414
449
|
const candidate = ice_1.IceCandidate.fromJSON(candidateMessage);
|
|
415
|
-
|
|
450
|
+
for (const iceTransport of this.iceTransports) {
|
|
451
|
+
await iceTransport.addRemoteCandidate(candidate);
|
|
452
|
+
}
|
|
416
453
|
}
|
|
417
454
|
async connect() {
|
|
418
455
|
if (this.masterTransportEstablished)
|
|
419
456
|
return;
|
|
420
|
-
const dtlsTransport = this.dtlsTransport;
|
|
421
|
-
const iceTransport = dtlsTransport.iceTransport;
|
|
422
457
|
this.setConnectionState("connecting");
|
|
423
|
-
await
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
458
|
+
await Promise.all(this.dtlsTransports.map(async (dtlsTransport) => {
|
|
459
|
+
const { iceTransport } = dtlsTransport;
|
|
460
|
+
await iceTransport.start().catch((err) => {
|
|
461
|
+
log("iceTransport.start failed", err);
|
|
462
|
+
throw err;
|
|
463
|
+
});
|
|
464
|
+
await dtlsTransport.start().catch((err) => {
|
|
465
|
+
log("dtlsTransport.start failed", err);
|
|
466
|
+
throw err;
|
|
467
|
+
});
|
|
468
|
+
if (this.sctpTransport &&
|
|
469
|
+
this.sctpRemotePort &&
|
|
470
|
+
this.sctpTransport.dtlsTransport.id === dtlsTransport.id) {
|
|
471
|
+
await this.sctpTransport.start(this.sctpRemotePort);
|
|
472
|
+
await this.sctpTransport.sctp.stateChanged.connected.asPromise();
|
|
473
|
+
log("sctp connected");
|
|
474
|
+
}
|
|
475
|
+
}));
|
|
438
476
|
this.masterTransportEstablished = true;
|
|
439
477
|
this.setConnectionState("connected");
|
|
440
478
|
}
|
|
441
|
-
|
|
479
|
+
getLocalRtpParams(transceiver) {
|
|
442
480
|
if (transceiver.mid == undefined)
|
|
443
481
|
throw new Error("mid not assigned");
|
|
444
482
|
const rtp = {
|
|
@@ -449,12 +487,7 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
449
487
|
};
|
|
450
488
|
return rtp;
|
|
451
489
|
}
|
|
452
|
-
|
|
453
|
-
if (transceiver.mLineIndex == undefined)
|
|
454
|
-
throw new Error("mLineIndex not assigned");
|
|
455
|
-
const media = remoteDescription.media[transceiver.mLineIndex];
|
|
456
|
-
if (!media)
|
|
457
|
-
throw new Error("media line not exist");
|
|
490
|
+
getRemoteRtpParams(media, transceiver) {
|
|
458
491
|
const receiveParameters = {
|
|
459
492
|
muxId: media.rtp.muxId,
|
|
460
493
|
rtcp: media.rtp.rtcp,
|
|
@@ -483,115 +516,79 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
483
516
|
const remoteSdp = sdp_1.SessionDescription.parse(sessionDescription.sdp);
|
|
484
517
|
remoteSdp.type = sessionDescription.type;
|
|
485
518
|
this.validateDescription(remoteSdp, false);
|
|
519
|
+
if (remoteSdp.type === "answer") {
|
|
520
|
+
this.currentRemoteDescription = remoteSdp;
|
|
521
|
+
this.pendingRemoteDescription = undefined;
|
|
522
|
+
}
|
|
523
|
+
else {
|
|
524
|
+
this.pendingRemoteDescription = remoteSdp;
|
|
525
|
+
}
|
|
526
|
+
const bundle = remoteSdp.group.find((g) => g.semantic === "BUNDLE" && this.configuration.bundlePolicy !== "disable");
|
|
527
|
+
let bundleTransport;
|
|
486
528
|
// # apply description
|
|
487
|
-
|
|
529
|
+
await Promise.all((0, helper_1.enumerate)(remoteSdp.media).map(async ([i, remoteMedia]) => {
|
|
530
|
+
let dtlsTransport;
|
|
488
531
|
if (["audio", "video"].includes(remoteMedia.kind)) {
|
|
489
|
-
|
|
490
|
-
[undefined, remoteMedia.rtp.muxId].includes(t.mid))
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
});
|
|
496
|
-
this.onRemoteTransceiverAdded.execute(transceiver);
|
|
497
|
-
this.onTransceiver.execute(transceiver);
|
|
498
|
-
return transceiver;
|
|
499
|
-
})();
|
|
500
|
-
if (!transceiver.mid) {
|
|
501
|
-
transceiver.mid = remoteMedia.rtp.muxId;
|
|
502
|
-
transceiver.mLineIndex = i;
|
|
503
|
-
}
|
|
504
|
-
// # negotiate codecs
|
|
505
|
-
transceiver.codecs = remoteMedia.rtp.codecs.filter((remoteCodec) => {
|
|
506
|
-
const localCodecs = this.configuration.codecs[remoteMedia.kind] || [];
|
|
507
|
-
const existCodec = (0, exports.findCodecByMimeType)(localCodecs, remoteCodec);
|
|
508
|
-
if (!existCodec)
|
|
509
|
-
return false;
|
|
510
|
-
if (existCodec?.name.toLowerCase() === "rtx") {
|
|
511
|
-
const params = (0, _1.codecParametersFromString)(existCodec.parameters ?? "");
|
|
512
|
-
const pt = params["apt"];
|
|
513
|
-
const origin = remoteMedia.rtp.codecs.find((c) => c.payloadType === pt);
|
|
514
|
-
if (!origin)
|
|
515
|
-
return false;
|
|
516
|
-
return !!(0, exports.findCodecByMimeType)(localCodecs, origin);
|
|
517
|
-
}
|
|
518
|
-
return true;
|
|
519
|
-
});
|
|
520
|
-
log("negotiated codecs", transceiver.codecs);
|
|
521
|
-
if (transceiver.codecs.length === 0) {
|
|
522
|
-
throw new Error("negotiate codecs failed.");
|
|
523
|
-
}
|
|
524
|
-
transceiver.headerExtensions = remoteMedia.rtp.headerExtensions.filter((extension) => (this.configuration.headerExtensions[remoteMedia.kind] || []).find((v) => v.uri === extension.uri));
|
|
525
|
-
// # configure direction
|
|
526
|
-
const mediaDirection = remoteMedia.direction || "inactive";
|
|
527
|
-
const direction = (0, utils_1.reverseDirection)(mediaDirection);
|
|
528
|
-
if (["answer", "pranswer"].includes(remoteSdp.type)) {
|
|
529
|
-
transceiver.currentDirection = direction;
|
|
530
|
-
}
|
|
531
|
-
else {
|
|
532
|
-
transceiver.offerDirection = direction;
|
|
533
|
-
}
|
|
534
|
-
const localParams = this.localRtp(transceiver);
|
|
535
|
-
transceiver.sender.prepareSend(localParams);
|
|
536
|
-
if (["recvonly", "sendrecv"].includes(transceiver.direction)) {
|
|
537
|
-
const remotePrams = this.remoteRtp(remoteSdp, transceiver);
|
|
538
|
-
// register simulcast receiver
|
|
539
|
-
remoteMedia.simulcastParameters.forEach((param) => {
|
|
540
|
-
this.router.registerRtpReceiverByRid(transceiver, param, remotePrams);
|
|
532
|
+
let transceiver = this.transceivers.find((t) => t.kind === remoteMedia.kind &&
|
|
533
|
+
[undefined, remoteMedia.rtp.muxId].includes(t.mid));
|
|
534
|
+
if (!transceiver) {
|
|
535
|
+
// create remote transceiver
|
|
536
|
+
transceiver = this.addTransceiver(remoteMedia.kind, {
|
|
537
|
+
direction: "recvonly",
|
|
541
538
|
});
|
|
542
|
-
|
|
543
|
-
// register ssrc receiver
|
|
544
|
-
this.router.registerRtpReceiverBySsrc(transceiver, remotePrams);
|
|
539
|
+
this.onRemoteTransceiverAdded.execute(transceiver);
|
|
545
540
|
}
|
|
546
|
-
if (
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
transceiver.
|
|
552
|
-
this.fireOnTrack(transceiver.receiver.track, transceiver, new track_1.MediaStream({
|
|
553
|
-
id: streamId,
|
|
554
|
-
tracks: [transceiver.receiver.track],
|
|
555
|
-
}));
|
|
541
|
+
if (bundle) {
|
|
542
|
+
if (!bundleTransport) {
|
|
543
|
+
bundleTransport = transceiver.dtlsTransport;
|
|
544
|
+
}
|
|
545
|
+
else {
|
|
546
|
+
transceiver.setDtlsTransport(bundleTransport);
|
|
556
547
|
}
|
|
557
548
|
}
|
|
558
|
-
transceiver.
|
|
549
|
+
dtlsTransport = transceiver.dtlsTransport;
|
|
550
|
+
this.setRemoteRTP(transceiver, remoteMedia, remoteSdp.type, i);
|
|
559
551
|
}
|
|
560
552
|
else if (remoteMedia.kind === "application") {
|
|
561
|
-
// # configure sctp
|
|
562
|
-
this.sctpRemotePort = remoteMedia.sctpPort;
|
|
563
|
-
if (!this.sctpRemotePort) {
|
|
564
|
-
throw new Error("sctpRemotePort not exist");
|
|
565
|
-
}
|
|
566
553
|
if (!this.sctpTransport) {
|
|
567
554
|
this.sctpTransport = this.createSctpTransport();
|
|
568
555
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
556
|
+
if (bundle) {
|
|
557
|
+
if (!bundleTransport) {
|
|
558
|
+
bundleTransport = this.sctpTransport.dtlsTransport;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
this.sctpTransport.setDtlsTransport(bundleTransport);
|
|
562
|
+
}
|
|
572
563
|
}
|
|
564
|
+
dtlsTransport = this.sctpTransport.dtlsTransport;
|
|
565
|
+
this.setRemoteSCTP(remoteMedia, this.sctpTransport);
|
|
573
566
|
}
|
|
567
|
+
else {
|
|
568
|
+
throw new Error("invalid media kind");
|
|
569
|
+
}
|
|
570
|
+
const iceTransport = dtlsTransport.iceTransport;
|
|
574
571
|
if (remoteMedia.iceParams && remoteMedia.dtlsParams) {
|
|
575
|
-
|
|
576
|
-
|
|
572
|
+
iceTransport.setRemoteParams(remoteMedia.iceParams);
|
|
573
|
+
dtlsTransport.setRemoteParams(remoteMedia.dtlsParams);
|
|
577
574
|
// One agent full, one lite: The full agent MUST take the controlling role, and the lite agent MUST take the controlled role
|
|
578
575
|
// RFC 8445 S6.1.1
|
|
579
576
|
if (remoteMedia.iceParams?.iceLite) {
|
|
580
|
-
|
|
577
|
+
iceTransport.connection.iceControlling = true;
|
|
581
578
|
}
|
|
582
579
|
}
|
|
583
580
|
// # add ICE candidates
|
|
584
|
-
remoteMedia.iceCandidates.forEach(
|
|
585
|
-
await
|
|
581
|
+
remoteMedia.iceCandidates.forEach(iceTransport.addRemoteCandidate);
|
|
582
|
+
await iceTransport.iceGather.gather();
|
|
586
583
|
if (remoteMedia.iceCandidatesComplete) {
|
|
587
|
-
await
|
|
584
|
+
await iceTransport.addRemoteCandidate(undefined);
|
|
588
585
|
}
|
|
589
586
|
// # set DTLS role
|
|
590
587
|
if (remoteSdp.type === "answer" && remoteMedia.dtlsParams?.role) {
|
|
591
|
-
|
|
588
|
+
dtlsTransport.role =
|
|
592
589
|
remoteMedia.dtlsParams.role === "client" ? "server" : "client";
|
|
593
590
|
}
|
|
594
|
-
}
|
|
591
|
+
}));
|
|
595
592
|
// connect transports
|
|
596
593
|
if (remoteSdp.type === "answer") {
|
|
597
594
|
log("caller start connect");
|
|
@@ -606,18 +603,83 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
606
603
|
else if (remoteSdp.type === "answer") {
|
|
607
604
|
this.setSignalingState("stable");
|
|
608
605
|
}
|
|
609
|
-
if (remoteSdp.type === "answer") {
|
|
610
|
-
this.currentRemoteDescription = remoteSdp;
|
|
611
|
-
this.pendingRemoteDescription = undefined;
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
this.pendingRemoteDescription = remoteSdp;
|
|
615
|
-
}
|
|
616
606
|
this.negotiationneeded = false;
|
|
617
607
|
if (this.shouldNegotiationneeded) {
|
|
618
608
|
this.needNegotiation();
|
|
619
609
|
}
|
|
620
610
|
}
|
|
611
|
+
setRemoteRTP(transceiver, remoteMedia, type, mLineIndex) {
|
|
612
|
+
if (!transceiver.mid) {
|
|
613
|
+
transceiver.mid = remoteMedia.rtp.muxId;
|
|
614
|
+
transceiver.mLineIndex = mLineIndex;
|
|
615
|
+
}
|
|
616
|
+
// # negotiate codecs
|
|
617
|
+
transceiver.codecs = remoteMedia.rtp.codecs.filter((remoteCodec) => {
|
|
618
|
+
const localCodecs = this.configuration.codecs[remoteMedia.kind] || [];
|
|
619
|
+
const existCodec = (0, exports.findCodecByMimeType)(localCodecs, remoteCodec);
|
|
620
|
+
if (!existCodec)
|
|
621
|
+
return false;
|
|
622
|
+
if (existCodec?.name.toLowerCase() === "rtx") {
|
|
623
|
+
const params = (0, _1.codecParametersFromString)(existCodec.parameters ?? "");
|
|
624
|
+
const pt = params["apt"];
|
|
625
|
+
const origin = remoteMedia.rtp.codecs.find((c) => c.payloadType === pt);
|
|
626
|
+
if (!origin)
|
|
627
|
+
return false;
|
|
628
|
+
return !!(0, exports.findCodecByMimeType)(localCodecs, origin);
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
});
|
|
632
|
+
log("negotiated codecs", transceiver.codecs);
|
|
633
|
+
if (transceiver.codecs.length === 0) {
|
|
634
|
+
throw new Error("negotiate codecs failed.");
|
|
635
|
+
}
|
|
636
|
+
transceiver.headerExtensions = remoteMedia.rtp.headerExtensions.filter((extension) => (this.configuration.headerExtensions[remoteMedia.kind] || []).find((v) => v.uri === extension.uri));
|
|
637
|
+
// # configure direction
|
|
638
|
+
const mediaDirection = remoteMedia.direction || "inactive";
|
|
639
|
+
const direction = (0, utils_1.reverseDirection)(mediaDirection);
|
|
640
|
+
if (["answer", "pranswer"].includes(type)) {
|
|
641
|
+
transceiver.currentDirection = direction;
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
transceiver.offerDirection = direction;
|
|
645
|
+
}
|
|
646
|
+
const localParams = this.getLocalRtpParams(transceiver);
|
|
647
|
+
transceiver.sender.prepareSend(localParams);
|
|
648
|
+
if (["recvonly", "sendrecv"].includes(transceiver.direction)) {
|
|
649
|
+
const remotePrams = this.getRemoteRtpParams(remoteMedia, transceiver);
|
|
650
|
+
// register simulcast receiver
|
|
651
|
+
remoteMedia.simulcastParameters.forEach((param) => {
|
|
652
|
+
this.router.registerRtpReceiverByRid(transceiver, param, remotePrams);
|
|
653
|
+
});
|
|
654
|
+
transceiver.receiver.prepareReceive(remotePrams);
|
|
655
|
+
// register ssrc receiver
|
|
656
|
+
this.router.registerRtpReceiverBySsrc(transceiver, remotePrams);
|
|
657
|
+
}
|
|
658
|
+
if (["sendonly", "sendrecv"].includes(mediaDirection)) {
|
|
659
|
+
// assign msid
|
|
660
|
+
if (remoteMedia.msid != undefined) {
|
|
661
|
+
const [streamId, trackId] = remoteMedia.msid.split(" ");
|
|
662
|
+
transceiver.receiver.remoteStreamId = streamId;
|
|
663
|
+
transceiver.receiver.remoteTrackId = trackId;
|
|
664
|
+
this.fireOnTrack(transceiver.receiver.track, transceiver, new track_1.MediaStream({
|
|
665
|
+
id: streamId,
|
|
666
|
+
tracks: [transceiver.receiver.track],
|
|
667
|
+
}));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
transceiver.receiver.setupTWCC(remoteMedia.ssrc[0]?.ssrc);
|
|
671
|
+
}
|
|
672
|
+
setRemoteSCTP(remoteMedia, sctpTransport) {
|
|
673
|
+
// # configure sctp
|
|
674
|
+
this.sctpRemotePort = remoteMedia.sctpPort;
|
|
675
|
+
if (!this.sctpRemotePort) {
|
|
676
|
+
throw new Error("sctpRemotePort not exist");
|
|
677
|
+
}
|
|
678
|
+
sctpTransport.setRemotePort(this.sctpRemotePort);
|
|
679
|
+
if (!sctpTransport.mid) {
|
|
680
|
+
sctpTransport.mid = remoteMedia.rtp.muxId;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
621
683
|
validateDescription(description, isLocal) {
|
|
622
684
|
if (isLocal) {
|
|
623
685
|
if (description.type === "offer") {
|
|
@@ -656,7 +718,7 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
656
718
|
throw new Error();
|
|
657
719
|
const offerMedia = offer.media.map((v) => [v.kind, v.rtp.muxId]);
|
|
658
720
|
const answerMedia = description.media.map((v) => [v.kind, v.rtp.muxId]);
|
|
659
|
-
if (!(0,
|
|
721
|
+
if (!(0, isEqual_1.default)(offerMedia, answerMedia))
|
|
660
722
|
throw new Error("Media sections in answer do not match offer");
|
|
661
723
|
}
|
|
662
724
|
}
|
|
@@ -674,13 +736,18 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
674
736
|
addTransceiver(trackOrKind, options = {}) {
|
|
675
737
|
const kind = typeof trackOrKind === "string" ? trackOrKind : trackOrKind.kind;
|
|
676
738
|
const direction = options.direction || "sendrecv";
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
739
|
+
const dtlsTransport = this.createTransport([
|
|
740
|
+
const_1.SRTP_PROFILE.SRTP_AEAD_AES_128_GCM,
|
|
741
|
+
const_1.SRTP_PROFILE.SRTP_AES128_CM_HMAC_SHA1_80,
|
|
742
|
+
]);
|
|
743
|
+
const sender = new rtpSender_1.RTCRtpSender(trackOrKind);
|
|
744
|
+
const receiver = new rtpReceiver_1.RTCRtpReceiver(kind, sender.ssrc);
|
|
745
|
+
const transceiver = new rtpTransceiver_1.RTCRtpTransceiver(kind, dtlsTransport, receiver, sender, direction);
|
|
680
746
|
transceiver.options = options;
|
|
681
747
|
this.router.registerRtpSender(transceiver.sender);
|
|
682
748
|
this.transceivers.push(transceiver);
|
|
683
749
|
this.onTransceiverAdded.execute(transceiver);
|
|
750
|
+
this.updateIceConnectionState();
|
|
684
751
|
this.needNegotiation();
|
|
685
752
|
return transceiver;
|
|
686
753
|
}
|
|
@@ -735,54 +802,72 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
735
802
|
return transceiver.sender;
|
|
736
803
|
}
|
|
737
804
|
}
|
|
805
|
+
async ensureCerts() {
|
|
806
|
+
const ensureCert = async (dtlsTransport) => {
|
|
807
|
+
if (this.certificates.length === 0) {
|
|
808
|
+
const localCertificate = await dtlsTransport.setupCertificate();
|
|
809
|
+
this.certificates.push(localCertificate);
|
|
810
|
+
}
|
|
811
|
+
else {
|
|
812
|
+
dtlsTransport.localCertificate = this.certificates[0];
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
for (const dtlsTransport of this.dtlsTransports) {
|
|
816
|
+
await ensureCert(dtlsTransport);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
738
819
|
async createAnswer() {
|
|
739
820
|
this.assertNotClosed();
|
|
740
|
-
if (!["have-remote-offer", "have-local-pranswer"].includes(this.signalingState)
|
|
741
|
-
!this.dtlsTransport)
|
|
821
|
+
if (!["have-remote-offer", "have-local-pranswer"].includes(this.signalingState)) {
|
|
742
822
|
throw new Error("createAnswer failed");
|
|
743
|
-
if (this.certificates.length === 0) {
|
|
744
|
-
await this.dtlsTransport.setupCertificate();
|
|
745
823
|
}
|
|
824
|
+
if (!this._remoteDescription) {
|
|
825
|
+
throw new Error("wrong state");
|
|
826
|
+
}
|
|
827
|
+
await this.ensureCerts();
|
|
746
828
|
const description = new sdp_1.SessionDescription();
|
|
747
829
|
(0, sdp_1.addSDPHeader)("answer", description);
|
|
748
|
-
this._remoteDescription
|
|
830
|
+
this._remoteDescription.media.forEach((remoteMedia) => {
|
|
749
831
|
let dtlsTransport;
|
|
750
832
|
let media;
|
|
751
|
-
if (["audio", "video"].includes(
|
|
752
|
-
const transceiver = this.getTransceiverByMid(
|
|
833
|
+
if (["audio", "video"].includes(remoteMedia.kind)) {
|
|
834
|
+
const transceiver = this.getTransceiverByMid(remoteMedia.rtp.muxId);
|
|
753
835
|
media = createMediaDescriptionForTransceiver(transceiver, this.cname, (0, utils_1.andDirection)(transceiver.direction, transceiver.offerDirection), transceiver.mid);
|
|
754
|
-
if (!transceiver.dtlsTransport)
|
|
755
|
-
throw new Error();
|
|
756
836
|
dtlsTransport = transceiver.dtlsTransport;
|
|
757
837
|
}
|
|
758
|
-
else if (
|
|
759
|
-
if (!this.sctpTransport || !this.sctpTransport.mid)
|
|
760
|
-
throw new Error();
|
|
838
|
+
else if (remoteMedia.kind === "application") {
|
|
839
|
+
if (!this.sctpTransport || !this.sctpTransport.mid) {
|
|
840
|
+
throw new Error("sctpTransport not found");
|
|
841
|
+
}
|
|
761
842
|
media = createMediaDescriptionForSctp(this.sctpTransport, this.sctpTransport.mid);
|
|
762
843
|
dtlsTransport = this.sctpTransport.dtlsTransport;
|
|
763
844
|
}
|
|
764
|
-
else
|
|
765
|
-
throw new Error();
|
|
845
|
+
else {
|
|
846
|
+
throw new Error("invalid kind");
|
|
847
|
+
}
|
|
766
848
|
// # determine DTLS role, or preserve the currently configured role
|
|
767
|
-
if (!media.dtlsParams)
|
|
768
|
-
throw new Error();
|
|
849
|
+
if (!media.dtlsParams) {
|
|
850
|
+
throw new Error("dtlsParams missing");
|
|
851
|
+
}
|
|
769
852
|
if (dtlsTransport.role === "auto") {
|
|
770
853
|
media.dtlsParams.role = "client";
|
|
771
854
|
}
|
|
772
855
|
else {
|
|
773
856
|
media.dtlsParams.role = dtlsTransport.role;
|
|
774
857
|
}
|
|
775
|
-
media.simulcastParameters =
|
|
858
|
+
media.simulcastParameters = remoteMedia.simulcastParameters.map((v) => ({
|
|
776
859
|
...v,
|
|
777
860
|
direction: (0, utils_1.reverseSimulcastDirection)(v.direction),
|
|
778
861
|
}));
|
|
779
862
|
description.media.push(media);
|
|
780
863
|
});
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
864
|
+
if (this.configuration.bundlePolicy !== "disable") {
|
|
865
|
+
const bundle = new sdp_1.GroupDescription("BUNDLE", []);
|
|
866
|
+
description.media.forEach((media) => {
|
|
867
|
+
bundle.items.push(media.rtp.muxId);
|
|
868
|
+
});
|
|
869
|
+
description.group.push(bundle);
|
|
870
|
+
}
|
|
786
871
|
return description.toJSON();
|
|
787
872
|
}
|
|
788
873
|
async close() {
|
|
@@ -798,26 +883,85 @@ class RTCPeerConnection extends helper_1.EventTarget {
|
|
|
798
883
|
if (this.sctpTransport) {
|
|
799
884
|
await this.sctpTransport.stop();
|
|
800
885
|
}
|
|
801
|
-
|
|
802
|
-
|
|
886
|
+
for (const dtlsTransport of this.dtlsTransports) {
|
|
887
|
+
await dtlsTransport.stop();
|
|
888
|
+
await dtlsTransport.iceTransport.stop();
|
|
889
|
+
}
|
|
803
890
|
this.dispose();
|
|
804
891
|
log("peerConnection closed");
|
|
805
892
|
}
|
|
806
893
|
assertNotClosed() {
|
|
807
|
-
if (this.isClosed)
|
|
894
|
+
if (this.isClosed) {
|
|
808
895
|
throw new Error("RTCPeerConnection is closed");
|
|
896
|
+
}
|
|
809
897
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
898
|
+
// https://w3c.github.io/webrtc-pc/#dom-rtcicegatheringstate
|
|
899
|
+
updateIceGatheringState() {
|
|
900
|
+
const all = this.iceTransports;
|
|
901
|
+
function allMatch(...state) {
|
|
902
|
+
return (all.filter((check) => state.includes(check.iceGather.gatheringState))
|
|
903
|
+
.length === all.length);
|
|
904
|
+
}
|
|
905
|
+
let newState;
|
|
906
|
+
if (all.length && allMatch("complete")) {
|
|
907
|
+
newState = "complete";
|
|
908
|
+
}
|
|
909
|
+
else if (!all.length || allMatch("new", "complete")) {
|
|
910
|
+
newState = "new";
|
|
911
|
+
}
|
|
912
|
+
else if (all.map((check) => check.iceGather.gatheringState).includes("gathering")) {
|
|
913
|
+
newState = "gathering";
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
newState = "new";
|
|
917
|
+
}
|
|
918
|
+
if (this.iceGatheringState === newState) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
log("iceGatheringStateChange", newState);
|
|
922
|
+
this.iceGatheringState = newState;
|
|
923
|
+
this.iceGatheringStateChange.execute(newState);
|
|
924
|
+
this.emit("icegatheringstatechange", newState);
|
|
815
925
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
926
|
+
// https://w3c.github.io/webrtc-pc/#dom-rtciceconnectionstate
|
|
927
|
+
updateIceConnectionState() {
|
|
928
|
+
const all = this.iceTransports;
|
|
929
|
+
let newState;
|
|
930
|
+
function allMatch(...state) {
|
|
931
|
+
return (all.filter((check) => state.includes(check.state)).length === all.length);
|
|
932
|
+
}
|
|
933
|
+
if (this.connectionState === "closed") {
|
|
934
|
+
newState = "closed";
|
|
935
|
+
}
|
|
936
|
+
else if (allMatch("failed")) {
|
|
937
|
+
newState = "failed";
|
|
938
|
+
}
|
|
939
|
+
else if (allMatch("disconnected")) {
|
|
940
|
+
newState = "disconnected";
|
|
941
|
+
}
|
|
942
|
+
else if (allMatch("new", "closed")) {
|
|
943
|
+
newState = "new";
|
|
944
|
+
}
|
|
945
|
+
else if (allMatch("new", "checking")) {
|
|
946
|
+
newState = "checking";
|
|
947
|
+
}
|
|
948
|
+
else if (allMatch("completed", "closed")) {
|
|
949
|
+
newState = "completed";
|
|
950
|
+
}
|
|
951
|
+
else if (allMatch("connected", "completed", "closed")) {
|
|
952
|
+
newState = "connected";
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
// unreachable?
|
|
956
|
+
newState = "new";
|
|
957
|
+
}
|
|
958
|
+
if (this.iceConnectionState === newState) {
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
log("iceConnectionStateChange", newState);
|
|
962
|
+
this.iceConnectionState = newState;
|
|
963
|
+
this.iceConnectionStateChange.execute(newState);
|
|
964
|
+
this.emit("iceconnectionstatechange", newState);
|
|
821
965
|
}
|
|
822
966
|
setSignalingState(state) {
|
|
823
967
|
log("signalingStateChange", state);
|
|
@@ -958,5 +1102,6 @@ exports.defaultPeerConfig = {
|
|
|
958
1102
|
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
|
|
959
1103
|
icePortRange: undefined,
|
|
960
1104
|
dtls: {},
|
|
1105
|
+
bundlePolicy: "max-compat",
|
|
961
1106
|
};
|
|
962
1107
|
//# sourceMappingURL=peerConnection.js.map
|