werift 0.15.3 → 0.15.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.
@@ -230,11 +230,19 @@ export class RTCPeerConnection extends EventTarget {
230
230
 
231
231
  async createOffer() {
232
232
  await this.ensureCerts();
233
+ const description = this.buildOfferSdp();
234
+ return description.toJSON();
235
+ }
233
236
 
237
+ buildOfferSdp() {
234
238
  this.transceivers.forEach((transceiver) => {
235
- transceiver.codecs = this.configuration.codecs[transceiver.kind];
236
- transceiver.headerExtensions =
237
- this.configuration.headerExtensions[transceiver.kind];
239
+ if (transceiver.codecs.length === 0) {
240
+ transceiver.codecs = this.configuration.codecs[transceiver.kind];
241
+ }
242
+ if (transceiver.headerExtensions.length === 0) {
243
+ transceiver.headerExtensions =
244
+ this.configuration.headerExtensions[transceiver.kind];
245
+ }
238
246
  });
239
247
 
240
248
  const description = new SessionDescription();
@@ -253,22 +261,24 @@ export class RTCPeerConnection extends EventTarget {
253
261
  return;
254
262
  }
255
263
  if (m.kind === "application") {
264
+ if (!this.sctpTransport) {
265
+ throw new Error("sctpTransport not found");
266
+ }
267
+ this.sctpTransport.mLineIndex = i;
256
268
  description.media.push(
257
- createMediaDescriptionForSctp(this.sctpTransport!, mid)
269
+ createMediaDescriptionForSctp(this.sctpTransport)
258
270
  );
259
271
  } else {
260
272
  const transceiver = this.getTransceiverByMid(mid);
261
273
  if (!transceiver) {
262
- log("transceiver by mid not found", mid);
263
- return;
274
+ throw new Error("transceiver not found");
264
275
  }
265
276
  transceiver.mLineIndex = i;
266
277
  description.media.push(
267
278
  createMediaDescriptionForTransceiver(
268
279
  transceiver,
269
280
  this.cname,
270
- transceiver.direction,
271
- mid
281
+ transceiver.direction
272
282
  )
273
283
  );
274
284
  }
@@ -279,26 +289,27 @@ export class RTCPeerConnection extends EventTarget {
279
289
  .filter((t) => !description.media.find((m) => m.rtp.muxId === t.mid))
280
290
  .forEach((transceiver) => {
281
291
  transceiver.mLineIndex = description.media.length;
292
+ if (transceiver.mid == undefined) {
293
+ transceiver.mid = allocateMid(this.seenMid) + "_srtp";
294
+ }
282
295
  description.media.push(
283
296
  createMediaDescriptionForTransceiver(
284
297
  transceiver,
285
298
  this.cname,
286
- transceiver.direction,
287
- allocateMid(this.seenMid)
299
+ transceiver.direction
288
300
  )
289
301
  );
290
302
  });
291
303
 
292
304
  if (
293
305
  this.sctpTransport &&
294
- !description.media.find((m) => this.sctpTransport!.mid === m.rtp.muxId)
306
+ !description.media.find((m) => m.kind === "application")
295
307
  ) {
296
- description.media.push(
297
- createMediaDescriptionForSctp(
298
- this.sctpTransport,
299
- allocateMid(this.seenMid)
300
- )
301
- );
308
+ this.sctpTransport.mLineIndex = description.media.length;
309
+ if (this.sctpTransport.mid == undefined) {
310
+ this.sctpTransport.mid = allocateMid(this.seenMid) + "_sctp";
311
+ }
312
+ description.media.push(createMediaDescriptionForSctp(this.sctpTransport));
302
313
  }
303
314
 
304
315
  if (this.configuration.bundlePolicy !== "disable") {
@@ -309,7 +320,7 @@ export class RTCPeerConnection extends EventTarget {
309
320
  description.group.push(bundle);
310
321
  }
311
322
 
312
- return description.toJSON();
323
+ return description;
313
324
  }
314
325
 
315
326
  createDataChannel(
@@ -423,14 +434,19 @@ export class RTCPeerConnection extends EventTarget {
423
434
 
424
435
  iceTransport.iceGather.onIceCandidate = (candidate) => {
425
436
  if (!this.localDescription) return;
426
- const sdp = SessionDescription.parse(this.localDescription.sdp);
427
- const media = sdp.media[0];
428
- if (!media) {
429
- log("media not exist");
430
- return;
437
+ const transceiver = this.transceivers.find(
438
+ (t) => t.dtlsTransport.iceTransport.id === iceTransport.id
439
+ );
440
+ if (transceiver) {
441
+ candidate.sdpMLineIndex = transceiver.mLineIndex;
442
+ candidate.sdpMid = transceiver.mid;
443
+ }
444
+ if (
445
+ this.sctpTransport?.dtlsTransport.iceTransport.id === iceTransport.id
446
+ ) {
447
+ candidate.sdpMLineIndex = this.sctpTransport.mLineIndex;
448
+ candidate.sdpMid = this.sctpTransport.mid;
431
449
  }
432
- candidate.sdpMLineIndex = 0;
433
- candidate.sdpMid = media.rtp.muxId;
434
450
  candidate.foundation = "candidate:" + candidate.foundation;
435
451
 
436
452
  this.onIceCandidate.execute(candidate.toJSON());
@@ -541,9 +557,10 @@ export class RTCPeerConnection extends EventTarget {
541
557
  this.setLocal(description);
542
558
 
543
559
  // # gather candidates
544
- for (const iceTransport of this.iceTransports) {
545
- await iceTransport.iceGather.gather();
546
- }
560
+ await Promise.all(
561
+ this.iceTransports.map((iceTransport) => iceTransport.iceGather.gather())
562
+ );
563
+
547
564
  description.media
548
565
  .filter((m) => ["audio", "video"].includes(m.kind))
549
566
  .forEach((m, i) => {
@@ -581,10 +598,54 @@ export class RTCPeerConnection extends EventTarget {
581
598
  }
582
599
  }
583
600
 
601
+ private getTransportByMid(mid: string) {
602
+ let iceTransport: RTCIceTransport | undefined;
603
+
604
+ const transceiver = this.transceivers.find((t) => t.mid === mid);
605
+ if (transceiver) {
606
+ iceTransport = transceiver.dtlsTransport.iceTransport;
607
+ } else if (!iceTransport && this.sctpTransport?.mid === mid) {
608
+ iceTransport = this.sctpTransport?.dtlsTransport.iceTransport;
609
+ }
610
+
611
+ return iceTransport;
612
+ }
613
+
614
+ private getTransportByMLineIndex(index: number) {
615
+ const sdp = this.buildOfferSdp();
616
+ const media = sdp.media[index];
617
+ if (!media) {
618
+ return;
619
+ }
620
+ const transport = this.getTransportByMid(media.rtp.muxId!);
621
+
622
+ return transport;
623
+ }
624
+
584
625
  async addIceCandidate(candidateMessage: RTCIceCandidate) {
585
626
  const candidate = IceCandidate.fromJSON(candidateMessage);
586
- for (const iceTransport of this.iceTransports) {
627
+ if (!candidate) {
628
+ return;
629
+ }
630
+
631
+ let iceTransport: RTCIceTransport | undefined;
632
+
633
+ if (typeof candidate.sdpMid === "number") {
634
+ iceTransport = this.getTransportByMid(candidate.sdpMid);
635
+ }
636
+
637
+ if (!iceTransport && typeof candidate.sdpMLineIndex === "number") {
638
+ iceTransport = this.getTransportByMLineIndex(candidate.sdpMLineIndex);
639
+ }
640
+
641
+ if (!iceTransport) {
642
+ iceTransport = this.iceTransports[0];
643
+ }
644
+
645
+ if (iceTransport) {
587
646
  await iceTransport.addRemoteCandidate(candidate);
647
+ } else {
648
+ log("iceTransport not found", candidate);
588
649
  }
589
650
  }
590
651
 
@@ -704,6 +765,7 @@ export class RTCPeerConnection extends EventTarget {
704
765
  transceiver = this.addTransceiver(remoteMedia.kind, {
705
766
  direction: "recvonly",
706
767
  });
768
+ transceiver.mid = remoteMedia.rtp.muxId;
707
769
  this.onRemoteTransceiverAdded.execute(transceiver);
708
770
  }
709
771
 
@@ -721,6 +783,7 @@ export class RTCPeerConnection extends EventTarget {
721
783
  } else if (remoteMedia.kind === "application") {
722
784
  if (!this.sctpTransport) {
723
785
  this.sctpTransport = this.createSctpTransport();
786
+ this.sctpTransport.mid = remoteMedia.rtp.muxId;
724
787
  }
725
788
 
726
789
  if (bundle) {
@@ -733,7 +796,7 @@ export class RTCPeerConnection extends EventTarget {
733
796
 
734
797
  dtlsTransport = this.sctpTransport.dtlsTransport;
735
798
 
736
- this.setRemoteSCTP(remoteMedia, this.sctpTransport);
799
+ this.setRemoteSCTP(remoteMedia, this.sctpTransport, i);
737
800
  } else {
738
801
  throw new Error("invalid media kind");
739
802
  }
@@ -878,7 +941,8 @@ export class RTCPeerConnection extends EventTarget {
878
941
 
879
942
  private setRemoteSCTP(
880
943
  remoteMedia: MediaDescription,
881
- sctpTransport: RTCSctpTransport
944
+ sctpTransport: RTCSctpTransport,
945
+ mLineIndex: number
882
946
  ) {
883
947
  // # configure sctp
884
948
  this.sctpRemotePort = remoteMedia.sctpPort;
@@ -887,6 +951,7 @@ export class RTCPeerConnection extends EventTarget {
887
951
  }
888
952
 
889
953
  sctpTransport.setRemotePort(this.sctpRemotePort);
954
+ sctpTransport.mLineIndex = mLineIndex;
890
955
  if (!sctpTransport.mid) {
891
956
  sctpTransport.mid = remoteMedia.rtp.muxId;
892
957
  }
@@ -1101,18 +1166,14 @@ export class RTCPeerConnection extends EventTarget {
1101
1166
  media = createMediaDescriptionForTransceiver(
1102
1167
  transceiver,
1103
1168
  this.cname,
1104
- andDirection(transceiver.direction, transceiver.offerDirection),
1105
- transceiver.mid!
1169
+ andDirection(transceiver.direction, transceiver.offerDirection)
1106
1170
  );
1107
1171
  dtlsTransport = transceiver.dtlsTransport;
1108
1172
  } else if (remoteMedia.kind === "application") {
1109
1173
  if (!this.sctpTransport || !this.sctpTransport.mid) {
1110
1174
  throw new Error("sctpTransport not found");
1111
1175
  }
1112
- media = createMediaDescriptionForSctp(
1113
- this.sctpTransport,
1114
- this.sctpTransport.mid
1115
- );
1176
+ media = createMediaDescriptionForSctp(this.sctpTransport);
1116
1177
 
1117
1178
  dtlsTransport = this.sctpTransport.dtlsTransport;
1118
1179
  } else {
@@ -1282,8 +1343,7 @@ export class RTCPeerConnection extends EventTarget {
1282
1343
  export function createMediaDescriptionForTransceiver(
1283
1344
  transceiver: RTCRtpTransceiver,
1284
1345
  cname: string,
1285
- direction: Direction,
1286
- mid: string
1346
+ direction: Direction
1287
1347
  ) {
1288
1348
  const media = new MediaDescription(
1289
1349
  transceiver.kind,
@@ -1296,7 +1356,7 @@ export function createMediaDescriptionForTransceiver(
1296
1356
  media.rtp = {
1297
1357
  codecs: transceiver.codecs,
1298
1358
  headerExtensions: transceiver.headerExtensions,
1299
- muxId: mid,
1359
+ muxId: transceiver.mid,
1300
1360
  };
1301
1361
  media.rtcpHost = "0.0.0.0";
1302
1362
  media.rtcpPort = 9;
@@ -1325,10 +1385,7 @@ export function createMediaDescriptionForTransceiver(
1325
1385
  return media;
1326
1386
  }
1327
1387
 
1328
- export function createMediaDescriptionForSctp(
1329
- sctp: RTCSctpTransport,
1330
- mid: string
1331
- ) {
1388
+ export function createMediaDescriptionForSctp(sctp: RTCSctpTransport) {
1332
1389
  const media = new MediaDescription(
1333
1390
  "application",
1334
1391
  DISCARD_PORT,
@@ -1336,7 +1393,7 @@ export function createMediaDescriptionForSctp(
1336
1393
  ["webrtc-datachannel"]
1337
1394
  );
1338
1395
  media.sctpPort = sctp.port;
1339
- media.rtp.muxId = mid;
1396
+ media.rtp.muxId = sctp.mid;
1340
1397
  media.sctpCapabilities = RTCSctpTransport.getCapabilities();
1341
1398
 
1342
1399
  addTransportDescription(media, sctp.dtlsTransport);
package/src/sdp.ts CHANGED
@@ -611,14 +611,6 @@ export function candidateFromSdp(sdp: string) {
611
611
 
612
612
  export class RTCSessionDescription {
613
613
  constructor(public sdp: string, public type: "offer" | "answer") {}
614
-
615
- get object() {
616
- return SessionDescription.parse(this.sdp);
617
- }
618
-
619
- static isThis(o: any) {
620
- if (typeof o?.sdp === "string") return true;
621
- }
622
614
  }
623
615
 
624
616
  export function addSDPHeader(
@@ -1,9 +1,11 @@
1
1
  import Event from "rx.mini";
2
+ import { v4 } from "uuid";
2
3
 
3
4
  import { Candidate, Connection, IceOptions } from "../../../ice/src";
4
5
  import { candidateFromSdp, candidateToSdp } from "../sdp";
5
6
 
6
7
  export class RTCIceTransport {
8
+ readonly id = v4();
7
9
  connection = this.gather.connection;
8
10
  state: RTCIceConnectionState = "new";
9
11
 
@@ -182,6 +184,14 @@ export class RTCIceCandidate {
182
184
  static isThis(o: any) {
183
185
  if (typeof o?.candidate === "string") return true;
184
186
  }
187
+
188
+ toJSON() {
189
+ return {
190
+ candidate: this.candidate,
191
+ sdpMid: this.sdpMid,
192
+ sdpMLineIndex: this.sdpMLineIndex,
193
+ };
194
+ }
185
195
  }
186
196
 
187
197
  export class IceCandidate {
@@ -28,9 +28,10 @@ export class RTCSctpTransport {
28
28
  sctp!: SCTP;
29
29
 
30
30
  readonly onDataChannel = new Event<[RTCDataChannel]>();
31
- readonly uuid = uuid.v4();
31
+ readonly id = uuid.v4();
32
32
 
33
33
  mid?: string;
34
+ mLineIndex?: number;
34
35
  bundled = false;
35
36
  dataChannels: { [key: number]: RTCDataChannel } = {};
36
37