werift 0.15.10 → 0.16.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.
Files changed (164) hide show
  1. package/lib/common/src/index.d.ts +2 -0
  2. package/lib/common/src/index.js +2 -0
  3. package/lib/common/src/index.js.map +1 -1
  4. package/lib/common/src/log.d.ts +11 -0
  5. package/lib/common/src/log.js +17 -0
  6. package/lib/common/src/log.js.map +1 -0
  7. package/lib/common/src/network.d.ts +7 -3
  8. package/lib/common/src/network.js +15 -7
  9. package/lib/common/src/network.js.map +1 -1
  10. package/lib/common/src/type.d.ts +3 -0
  11. package/lib/common/src/type.js +3 -0
  12. package/lib/common/src/type.js.map +1 -0
  13. package/lib/dtls/src/context/cipher.js.map +1 -1
  14. package/lib/dtls/src/flight/server/flight2.js +10 -0
  15. package/lib/dtls/src/flight/server/flight2.js.map +1 -1
  16. package/lib/ice/src/ice.d.ts +3 -0
  17. package/lib/ice/src/ice.js +9 -2
  18. package/lib/ice/src/ice.js.map +1 -1
  19. package/lib/ice/src/stun/protocol.d.ts +2 -1
  20. package/lib/ice/src/stun/protocol.js +3 -3
  21. package/lib/ice/src/stun/protocol.js.map +1 -1
  22. package/lib/ice/src/transport.d.ts +4 -2
  23. package/lib/ice/src/transport.js +8 -6
  24. package/lib/ice/src/transport.js.map +1 -1
  25. package/lib/ice/src/turn/protocol.d.ts +3 -1
  26. package/lib/ice/src/turn/protocol.js +2 -2
  27. package/lib/ice/src/turn/protocol.js.map +1 -1
  28. package/lib/ice/src/utils.d.ts +2 -1
  29. package/lib/ice/src/utils.js +2 -2
  30. package/lib/ice/src/utils.js.map +1 -1
  31. package/lib/rtp/src/codec/index.d.ts +18 -0
  32. package/lib/rtp/src/codec/index.js +81 -0
  33. package/lib/rtp/src/codec/index.js.map +1 -0
  34. package/lib/rtp/src/codec/vp8.d.ts +5 -3
  35. package/lib/rtp/src/codec/vp8.js +19 -5
  36. package/lib/rtp/src/codec/vp8.js.map +1 -1
  37. package/lib/rtp/src/container/webm.d.ts +6 -1
  38. package/lib/rtp/src/container/webm.js +9 -2
  39. package/lib/rtp/src/container/webm.js.map +1 -1
  40. package/lib/rtp/src/index.d.ts +2 -6
  41. package/lib/rtp/src/index.js +2 -6
  42. package/lib/rtp/src/index.js.map +1 -1
  43. package/lib/rtp/src/processor/base.d.ts +3 -1
  44. package/lib/rtp/src/processor/base.js +19 -6
  45. package/lib/rtp/src/processor/base.js.map +1 -1
  46. package/lib/rtp/src/processor/jitterBuffer.js +1 -2
  47. package/lib/rtp/src/processor/jitterBuffer.js.map +1 -1
  48. package/lib/rtp/src/processor/lipsync.js +22 -2
  49. package/lib/rtp/src/processor/lipsync.js.map +1 -1
  50. package/lib/rtp/src/processor/webm.d.ts +11 -7
  51. package/lib/rtp/src/processor/webm.js +16 -41
  52. package/lib/rtp/src/processor/webm.js.map +1 -1
  53. package/lib/rtp/src/processor_v2/depacketizer.d.ts +17 -0
  54. package/lib/rtp/src/processor_v2/depacketizer.js +84 -0
  55. package/lib/rtp/src/processor_v2/depacketizer.js.map +1 -0
  56. package/lib/rtp/src/processor_v2/index.d.ts +4 -0
  57. package/lib/rtp/src/processor_v2/index.js +21 -0
  58. package/lib/rtp/src/processor_v2/index.js.map +1 -0
  59. package/lib/rtp/src/processor_v2/jitterBuffer.d.ts +33 -0
  60. package/lib/rtp/src/processor_v2/jitterBuffer.js +154 -0
  61. package/lib/rtp/src/processor_v2/jitterBuffer.js.map +1 -0
  62. package/lib/rtp/src/processor_v2/source/base.d.ts +8 -0
  63. package/lib/rtp/src/processor_v2/source/base.js +16 -0
  64. package/lib/rtp/src/processor_v2/source/base.js.map +1 -0
  65. package/lib/rtp/src/processor_v2/source/index.d.ts +2 -0
  66. package/lib/rtp/src/processor_v2/source/index.js +6 -0
  67. package/lib/rtp/src/processor_v2/source/index.js.map +1 -0
  68. package/lib/rtp/src/processor_v2/source/rtp.d.ts +14 -0
  69. package/lib/rtp/src/processor_v2/source/rtp.js +24 -0
  70. package/lib/rtp/src/processor_v2/source/rtp.js.map +1 -0
  71. package/lib/rtp/src/processor_v2/webmLive.d.ts +51 -0
  72. package/lib/rtp/src/processor_v2/webmLive.js +154 -0
  73. package/lib/rtp/src/processor_v2/webmLive.js.map +1 -0
  74. package/lib/rtp/src/rtcp/header.d.ts +2 -1
  75. package/lib/rtp/src/rtcp/header.js +3 -2
  76. package/lib/rtp/src/rtcp/header.js.map +1 -1
  77. package/lib/rtp/src/rtcp/rr.d.ts +2 -0
  78. package/lib/rtp/src/rtcp/rr.js.map +1 -1
  79. package/lib/rtp/src/rtcp/rtcp.js +4 -4
  80. package/lib/rtp/src/rtcp/rtcp.js.map +1 -1
  81. package/lib/rtp/src/rtcp/rtpfb/index.js +1 -1
  82. package/lib/rtp/src/rtcp/rtpfb/index.js.map +1 -1
  83. package/lib/rtp/src/rtcp/rtpfb/nack.js +15 -7
  84. package/lib/rtp/src/rtcp/rtpfb/nack.js.map +1 -1
  85. package/lib/rtp/src/rtp/red/packet.d.ts +1 -0
  86. package/lib/rtp/src/rtp/red/packet.js.map +1 -1
  87. package/lib/rtp/src/rtp/rtp.d.ts +1 -0
  88. package/lib/rtp/src/rtp/rtp.js +27 -26
  89. package/lib/rtp/src/rtp/rtp.js.map +1 -1
  90. package/lib/rtp/src/srtp/cipher/ctr.d.ts +1 -1
  91. package/lib/rtp/src/srtp/cipher/ctr.js +14 -20
  92. package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
  93. package/lib/webrtc/src/dataChannel.js +1 -1
  94. package/lib/webrtc/src/dataChannel.js.map +1 -1
  95. package/lib/webrtc/src/media/extension/rtpExtension.d.ts +2 -0
  96. package/lib/webrtc/src/media/extension/rtpExtension.js +8 -1
  97. package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
  98. package/lib/webrtc/src/media/parameters.d.ts +2 -0
  99. package/lib/webrtc/src/media/parameters.js +1 -0
  100. package/lib/webrtc/src/media/parameters.js.map +1 -1
  101. package/lib/webrtc/src/media/receiver/nack.d.ts +10 -5
  102. package/lib/webrtc/src/media/receiver/nack.js +44 -27
  103. package/lib/webrtc/src/media/receiver/nack.js.map +1 -1
  104. package/lib/webrtc/src/media/receiver/receiverTwcc.js +1 -1
  105. package/lib/webrtc/src/media/receiver/receiverTwcc.js.map +1 -1
  106. package/lib/webrtc/src/media/receiver/red.d.ts +1 -1
  107. package/lib/webrtc/src/media/receiver/red.js +14 -3
  108. package/lib/webrtc/src/media/receiver/red.js.map +1 -1
  109. package/lib/webrtc/src/media/router.d.ts +10 -3
  110. package/lib/webrtc/src/media/router.js +2 -0
  111. package/lib/webrtc/src/media/router.js.map +1 -1
  112. package/lib/webrtc/src/media/rtpReceiver.d.ts +11 -3
  113. package/lib/webrtc/src/media/rtpReceiver.js +42 -23
  114. package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
  115. package/lib/webrtc/src/media/rtpSender.d.ts +23 -2
  116. package/lib/webrtc/src/media/rtpSender.js +34 -10
  117. package/lib/webrtc/src/media/rtpSender.js.map +1 -1
  118. package/lib/webrtc/src/media/rtpTransceiver.d.ts +5 -1
  119. package/lib/webrtc/src/media/rtpTransceiver.js +9 -9
  120. package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
  121. package/lib/webrtc/src/media/track.js +4 -2
  122. package/lib/webrtc/src/media/track.js.map +1 -1
  123. package/lib/webrtc/src/nonstandard/recorder/index.d.ts +5 -1
  124. package/lib/webrtc/src/nonstandard/recorder/index.js +2 -2
  125. package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
  126. package/lib/webrtc/src/nonstandard/recorder/writer/index.d.ts +1 -1
  127. package/lib/webrtc/src/nonstandard/recorder/writer/index.js +1 -1
  128. package/lib/webrtc/src/nonstandard/recorder/writer/index.js.map +1 -1
  129. package/lib/webrtc/src/nonstandard/recorder/writer/webm.d.ts +3 -3
  130. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +61 -41
  131. package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
  132. package/lib/webrtc/src/peerConnection.d.ts +13 -0
  133. package/lib/webrtc/src/peerConnection.js +40 -3
  134. package/lib/webrtc/src/peerConnection.js.map +1 -1
  135. package/lib/webrtc/src/sdp.d.ts +1 -0
  136. package/lib/webrtc/src/sdp.js +4 -0
  137. package/lib/webrtc/src/sdp.js.map +1 -1
  138. package/lib/webrtc/src/transport/dtls.js +6 -1
  139. package/lib/webrtc/src/transport/dtls.js.map +1 -1
  140. package/lib/webrtc/src/transport/sctp.js +1 -1
  141. package/lib/webrtc/src/transport/sctp.js.map +1 -1
  142. package/lib/webrtc/src/utils.d.ts +7 -2
  143. package/lib/webrtc/src/utils.js +9 -3
  144. package/lib/webrtc/src/utils.js.map +1 -1
  145. package/package.json +2 -2
  146. package/src/dataChannel.ts +1 -1
  147. package/src/media/extension/rtpExtension.ts +8 -0
  148. package/src/media/parameters.ts +3 -0
  149. package/src/media/receiver/nack.ts +45 -26
  150. package/src/media/receiver/receiverTwcc.ts +1 -1
  151. package/src/media/receiver/red.ts +14 -1
  152. package/src/media/router.ts +5 -3
  153. package/src/media/rtpReceiver.ts +59 -28
  154. package/src/media/rtpSender.ts +38 -12
  155. package/src/media/rtpTransceiver.ts +10 -8
  156. package/src/media/track.ts +6 -2
  157. package/src/nonstandard/recorder/index.ts +6 -2
  158. package/src/nonstandard/recorder/writer/index.ts +1 -1
  159. package/src/nonstandard/recorder/writer/webm.ts +105 -57
  160. package/src/peerConnection.ts +61 -7
  161. package/src/sdp.ts +3 -0
  162. package/src/transport/dtls.ts +5 -1
  163. package/src/transport/sctp.ts +1 -1
  164. package/src/utils.ts +8 -2
@@ -1,3 +1,4 @@
1
+ import debug from "debug";
1
2
  import range from "lodash/range";
2
3
  import Event from "rx.mini";
3
4
 
@@ -9,20 +10,27 @@ import {
9
10
  } from "../../../../rtp/src";
10
11
  import { RTCRtpReceiver } from "../rtpReceiver";
11
12
 
13
+ const log = debug("werift:packages/webrtc/src/media/receiver/nack.ts");
14
+
12
15
  const LOST_SIZE = 30 * 5;
13
16
 
14
- export class Nack {
17
+ export class NackHandler {
15
18
  private newEstSeqNum = 0;
16
- private _lost: { [seqNum: number]: number } = {};
17
- private nackLoop = setInterval(() => this.packetLost(), 20);
19
+ lost: { [seqNum: number]: number } = {};
20
+ private nackLoop = setInterval(() => this.sendNack(), 20);
18
21
 
19
22
  readonly onPacketLost = new Event<[GenericNack]>();
20
23
  mediaSourceSsrc?: number;
24
+ retryCount = 10;
21
25
 
22
26
  constructor(private receiver: RTCRtpReceiver) {}
23
27
 
24
- get lost() {
25
- return Object.keys(this._lost).map(Number);
28
+ get lostNumber() {
29
+ return Object.keys(this.lost).map(Number);
30
+ }
31
+
32
+ removeLost(sequenceNumber: number) {
33
+ delete this.lost[sequenceNumber];
26
34
  }
27
35
 
28
36
  addPacket(packet: RtpPacket) {
@@ -34,8 +42,8 @@ export class Nack {
34
42
  return;
35
43
  }
36
44
 
37
- if (this._lost[sequenceNumber]) {
38
- delete this._lost[sequenceNumber];
45
+ if (this.lost[sequenceNumber]) {
46
+ this.removeLost(sequenceNumber);
39
47
  return;
40
48
  }
41
49
 
@@ -44,48 +52,59 @@ export class Nack {
44
52
  } else if (sequenceNumber > uint16Add(this.newEstSeqNum, 1)) {
45
53
  // packet lost detected
46
54
  range(uint16Add(this.newEstSeqNum, 1), sequenceNumber).forEach((seq) => {
47
- this._lost[seq] = 1;
55
+ this.lost[seq] = 1;
48
56
  });
49
57
  this.receiver.sendRtcpPLI(this.mediaSourceSsrc);
50
58
 
51
59
  this.newEstSeqNum = sequenceNumber;
60
+ this.pruneLost();
61
+ }
62
+ }
52
63
 
53
- if (Object.keys(this._lost).length > LOST_SIZE) {
54
- this._lost = Object.entries(this._lost)
55
- .slice(-LOST_SIZE)
56
- .reduce((acc, [key, v]) => {
57
- acc[key] = v;
58
- return acc;
59
- }, {} as { [seqNum: number]: number });
60
- }
64
+ private pruneLost() {
65
+ if (Object.keys(this.lost).length > LOST_SIZE) {
66
+ this.lost = Object.entries(this.lost)
67
+ .slice(-LOST_SIZE)
68
+ .reduce((acc, [key, v]) => {
69
+ acc[key] = v;
70
+ return acc;
71
+ }, {} as { [seqNum: number]: number });
61
72
  }
62
73
  }
63
74
 
64
75
  close() {
65
76
  clearInterval(this.nackLoop);
77
+ this.lost = {};
66
78
  }
67
79
 
68
- private increment() {
69
- Object.keys(this._lost).forEach((seq) => {
70
- if (++this._lost[seq] > 10) {
71
- delete this._lost[seq];
72
- }
73
- });
80
+ private updateRetryCount() {
81
+ const res = Object.keys(this.lost)
82
+ .map((seq) => {
83
+ const count = this.lost[seq]++;
84
+ if (count > this.retryCount) {
85
+ delete this.lost[seq];
86
+ return seq;
87
+ }
88
+ })
89
+ .filter((v) => v != undefined);
90
+ if (res.length > 0) {
91
+ // log("failed to retransmit", res);
92
+ }
74
93
  }
75
94
 
76
- private packetLost() {
77
- if (this.lost.length > 0 && this.mediaSourceSsrc) {
95
+ private sendNack() {
96
+ if (this.lostNumber.length > 0 && this.mediaSourceSsrc) {
78
97
  const nack = new GenericNack({
79
98
  senderSsrc: this.receiver.rtcpSsrc,
80
99
  mediaSourceSsrc: this.mediaSourceSsrc,
81
- lost: this.lost,
100
+ lost: this.lostNumber,
82
101
  });
83
102
  const rtcp = new RtcpTransportLayerFeedback({
84
103
  feedback: nack,
85
104
  });
86
105
  this.receiver.dtlsTransport.sendRtcp([rtcp]);
87
106
 
88
- this.increment();
107
+ this.updateRetryCount();
89
108
  this.onPacketLost.execute(nack);
90
109
  }
91
110
  }
@@ -13,7 +13,7 @@ import {
13
13
  import { RTCDtlsTransport } from "../../transport/dtls";
14
14
  import { microTime } from "../../utils";
15
15
 
16
- const log = debug("werift/webrtc/media/receiver/receiverTwcc");
16
+ const log = debug("werift:packages/webrtc/media/receiver/receiverTwcc");
17
17
 
18
18
  type ExtensionInfo = { tsn: number; timestamp: number };
19
19
 
@@ -1,6 +1,17 @@
1
1
  import { Red, RtpHeader, RtpPacket, uint16Add, uint32Add } from "../..";
2
2
 
3
- export class RedHandler {
3
+ // 0 1 2 3
4
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
5
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
6
+ // |F| block PT | timestamp offset | block length |
7
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
8
+
9
+ // 0 1 2 3 4 5 6 7
10
+ // +-+-+-+-+-+-+-+-+
11
+ // |0| Block PT |
12
+ // +-+-+-+-+-+-+-+-+
13
+
14
+ export class AudioRedHandler {
4
15
  private readonly size = 150;
5
16
  private sequenceNumbers: number[] = [];
6
17
 
@@ -42,9 +53,11 @@ export class RedHandler {
42
53
  });
43
54
 
44
55
  const filtered = packets.filter((p) => {
56
+ // duplicate
45
57
  if (this.sequenceNumbers.includes(p.header.sequenceNumber)) {
46
58
  return false;
47
59
  } else {
60
+ // buffer overflow
48
61
  if (this.sequenceNumbers.length > this.size) {
49
62
  this.sequenceNumbers.shift();
50
63
  }
@@ -27,9 +27,9 @@ const log = debug("werift:packages/webrtc/src/media/router.ts");
27
27
  export type Extensions = { [uri: string]: number | string };
28
28
 
29
29
  export class RtpRouter {
30
- private ssrcTable: { [ssrc: number]: RTCRtpReceiver | RTCRtpSender } = {};
31
- private ridTable: { [rid: string]: RTCRtpReceiver | RTCRtpSender } = {};
32
- private extIdUriMap: { [id: number]: string } = {};
30
+ ssrcTable: { [ssrc: number]: RTCRtpReceiver | RTCRtpSender } = {};
31
+ ridTable: { [rid: string]: RTCRtpReceiver | RTCRtpSender } = {};
32
+ extIdUriMap: { [id: number]: string } = {};
33
33
 
34
34
  constructor() {}
35
35
 
@@ -110,6 +110,8 @@ export class RtpRouter {
110
110
  uri,
111
111
  value: bufferReader(extension.payload, [3])[0],
112
112
  };
113
+ default:
114
+ return { uri, value: 0 };
113
115
  }
114
116
  })
115
117
  .reduce((acc: { [uri: string]: any }, cur) => {
@@ -16,15 +16,15 @@ import {
16
16
  RtpHeader,
17
17
  RtpPacket,
18
18
  } from "../../../rtp/src";
19
- import { codecParametersFromString } from "..";
19
+ import { codecParametersFromString, PeerConfig } from "..";
20
20
  import { RTCDtlsTransport } from "../transport/dtls";
21
21
  import { Kind } from "../types/domain";
22
- import { compactNtp } from "../utils";
22
+ import { compactNtp, timestampSeconds } from "../utils";
23
23
  import { RTP_EXTENSION_URI } from "./extension/rtpExtension";
24
24
  import { RTCRtpCodecParameters, RTCRtpReceiveParameters } from "./parameters";
25
- import { Nack } from "./receiver/nack";
25
+ import { NackHandler } from "./receiver/nack";
26
26
  import { ReceiverTWCC } from "./receiver/receiverTwcc";
27
- import { RedHandler } from "./receiver/red";
27
+ import { AudioRedHandler } from "./receiver/red";
28
28
  import { StreamStatistics } from "./receiver/statistics";
29
29
  import { Extensions } from "./router";
30
30
  import { MediaStreamTrack } from "./track";
@@ -33,18 +33,26 @@ const log = debug("werift:packages/webrtc/src/media/rtpReceiver.ts");
33
33
 
34
34
  export class RTCRtpReceiver {
35
35
  private readonly codecs: { [pt: number]: RTCRtpCodecParameters } = {};
36
+ private get codecArray() {
37
+ return Object.values(this.codecs).sort(
38
+ (a, b) => a.payloadType - b.payloadType
39
+ );
40
+ }
36
41
  private readonly ssrcByRtx: { [rtxSsrc: number]: number } = {};
37
- private readonly nack = new Nack(this);
38
- private readonly redHandler = new RedHandler();
42
+ private readonly nack = new NackHandler(this);
43
+ private readonly redHandler = new AudioRedHandler();
39
44
 
40
45
  readonly type = "receiver";
41
46
  readonly uuid = uuid();
42
47
  readonly tracks: MediaStreamTrack[] = [];
43
48
  readonly trackBySSRC: { [ssrc: string]: MediaStreamTrack } = {};
44
49
  readonly trackByRID: { [rid: string]: MediaStreamTrack } = {};
45
- // last senderReport
46
- readonly lsr: { [ssrc: number]: number } = {};
47
- readonly lsrTime: { [ssrc: number]: number } = {};
50
+ /**last sender Report Timestamp
51
+ * compactNtp
52
+ */
53
+ readonly lastSRtimestamp: { [ssrc: number]: number } = {};
54
+ /**seconds */
55
+ readonly receiveLastSRTimestamp: { [ssrc: number]: number } = {};
48
56
  readonly onPacketLost = this.nack.onPacketLost;
49
57
  readonly onRtcp = new Event<[RtcpPacket]>();
50
58
 
@@ -63,7 +71,11 @@ export class RTCRtpReceiver {
63
71
  private rtcpCancel = new AbortController();
64
72
  private remoteStreams: { [ssrc: number]: StreamStatistics } = {};
65
73
 
66
- constructor(public kind: Kind, public rtcpSsrc: number) {}
74
+ constructor(
75
+ readonly config: PeerConfig,
76
+ public kind: Kind,
77
+ public rtcpSsrc: number
78
+ ) {}
67
79
 
68
80
  setDtlsTransport(dtls: RTCDtlsTransport) {
69
81
  this.dtlsTransport = dtls;
@@ -74,6 +86,10 @@ export class RTCRtpReceiver {
74
86
  return this.tracks[0];
75
87
  }
76
88
 
89
+ get nackEnabled() {
90
+ return this.codecArray[0].rtcpFeedback.find((f) => f.type === "nack");
91
+ }
92
+
77
93
  prepareReceive(params: RTCRtpReceiveParameters) {
78
94
  params.codecs.forEach((c) => {
79
95
  this.codecs[c.payloadType] = c;
@@ -136,13 +152,14 @@ export class RTCRtpReceiver {
136
152
 
137
153
  const reports = Object.entries(this.remoteStreams).map(
138
154
  ([ssrc, stream]) => {
139
- let lsr = 0,
140
- dlsr = 0;
141
- if (this.lsr[ssrc]) {
142
- lsr = this.lsr[ssrc];
143
- const delay = Date.now() / 1000 - this.lsrTime[ssrc];
144
- if (delay > 0 && delay < 65536) {
145
- dlsr = int(delay * 65536);
155
+ let lastSRtimestamp = 0,
156
+ delaySinceLastSR = 0;
157
+ if (this.lastSRtimestamp[ssrc]) {
158
+ lastSRtimestamp = this.lastSRtimestamp[ssrc];
159
+ const delaySeconds =
160
+ timestampSeconds() - this.receiveLastSRTimestamp[ssrc];
161
+ if (delaySeconds > 0 && delaySeconds < 65536) {
162
+ delaySinceLastSR = int(delaySeconds * 65536);
146
163
  }
147
164
  }
148
165
 
@@ -152,8 +169,8 @@ export class RTCRtpReceiver {
152
169
  packetsLost: stream.packets_lost,
153
170
  highestSequence: stream.max_seq,
154
171
  jitter: stream.jitter,
155
- lsr,
156
- dlsr,
172
+ lsr: lastSRtimestamp,
173
+ dlsr: delaySinceLastSR,
157
174
  });
158
175
  }
159
176
  );
@@ -161,6 +178,9 @@ export class RTCRtpReceiver {
161
178
  const packet = new RtcpRrPacket({ ssrc: this.rtcpSsrc, reports });
162
179
 
163
180
  try {
181
+ if (this.config.debug.receiverReportDelay) {
182
+ await setTimeout(this.config.debug.receiverReportDelay);
183
+ }
164
184
  await this.dtlsTransport.sendRtcp([packet]);
165
185
  } catch (error) {
166
186
  log("sendRtcp failed", error);
@@ -192,8 +212,10 @@ export class RTCRtpReceiver {
192
212
  case RtcpSrPacket.type:
193
213
  {
194
214
  const sr = packet as RtcpSrPacket;
195
- this.lsr[sr.ssrc] = compactNtp(sr.senderInfo.ntpTimestamp);
196
- this.lsrTime[sr.ssrc] = Date.now() / 1000;
215
+ this.lastSRtimestamp[sr.ssrc] = compactNtp(
216
+ sr.senderInfo.ntpTimestamp
217
+ );
218
+ this.receiveLastSRTimestamp[sr.ssrc] = timestampSeconds();
197
219
 
198
220
  const track = this.trackBySSRC[packet.ssrc];
199
221
  if (track) {
@@ -264,18 +286,27 @@ export class RTCRtpReceiver {
264
286
  let red: Red | undefined;
265
287
  if (codec.name.toLowerCase() === "red") {
266
288
  red = Red.deSerialize(packet.payload);
289
+ if (
290
+ !Object.keys(this.codecs).includes(
291
+ red.header.fields[0].blockPT.toString()
292
+ )
293
+ ) {
294
+ return;
295
+ }
267
296
  }
268
297
 
269
- // todo fix select use or not use nack
270
- if (track?.kind === "video") {
298
+ if (track?.kind === "video" && this.nackEnabled) {
271
299
  this.nack.addPacket(packet);
272
300
  }
273
301
 
274
302
  if (track) {
275
303
  if (red) {
276
- const payloads = this.redHandler.push(red, packet);
277
- for (const packet of payloads) {
278
- track.onReceiveRtp.execute(packet.clone());
304
+ if (track.kind === "audio") {
305
+ const payloads = this.redHandler.push(red, packet);
306
+ for (const packet of payloads) {
307
+ track.onReceiveRtp.execute(packet.clone());
308
+ }
309
+ } else {
279
310
  }
280
311
  } else {
281
312
  track.onReceiveRtp.execute(packet.clone());
@@ -291,11 +322,11 @@ export function unwrapRtx(rtx: RtpPacket, payloadType: number, ssrc: number) {
291
322
  new RtpHeader({
292
323
  payloadType,
293
324
  marker: rtx.header.marker,
294
- sequenceNumber: jspack.Unpack("!H", rtx.payload.slice(0, 2))[0],
325
+ sequenceNumber: jspack.Unpack("!H", rtx.payload.subarray(0, 2))[0],
295
326
  timestamp: rtx.header.timestamp,
296
327
  ssrc,
297
328
  }),
298
- rtx.payload.slice(2)
329
+ rtx.payload.subarray(2)
299
330
  );
300
331
  return packet;
301
332
  }
@@ -1,3 +1,25 @@
1
+ /**
2
+ [10 Nov 1995 11:33:25.125 UTC] [10 Nov 1995 11:33:36.5 UTC]
3
+ n SR(n) A=b710:8000 (46864.500 s)
4
+ ---------------------------------------------------------------->
5
+ v ^
6
+ ntp_sec =0xb44db705 v ^ dlsr=0x0005:4000 ( 5.250s)
7
+ ntp_frac=0x20000000 v ^ lsr =0xb705:2000 (46853.125s)
8
+ (3024992005.125 s) v ^
9
+ r v ^ RR(n)
10
+ ---------------------------------------------------------------->
11
+ |<-DLSR->|
12
+ (5.250 s)
13
+
14
+ A 0xb710:8000 (46864.500 s)
15
+ DLSR -0x0005:4000 ( 5.250 s)
16
+ LSR -0xb705:2000 (46853.125 s)
17
+ -------------------------------
18
+ delay 0x0006:2000 ( 6.125 s)
19
+
20
+ Figure 2: Example for round-trip time computation
21
+ */
22
+
1
23
  import { randomBytes } from "crypto";
2
24
  import debug from "debug";
3
25
  import { jspack } from "jspack";
@@ -33,7 +55,7 @@ import {
33
55
  import { codecParametersFromString } from "..";
34
56
  import { RTCDtlsTransport } from "../transport/dtls";
35
57
  import { Kind } from "../types/domain";
36
- import { compactNtp, milliTime, ntpTime } from "../utils";
58
+ import { compactNtp, milliTime, ntpTime, timestampSeconds } from "../utils";
37
59
  import { RTP_EXTENSION_URI } from "./extension/rtpExtension";
38
60
  import {
39
61
  RTCRtpCodecParameters,
@@ -77,8 +99,8 @@ export class RTCRtpSender {
77
99
  private disposeTrack?: () => void;
78
100
 
79
101
  // # stats
80
- private lsr?: number;
81
- private lsrTime: number = Date.now() / 1000;
102
+ private lastSRtimestamp?: number;
103
+ private lastSentSRTimestamp?: number;
82
104
  private ntpTimestamp = 0n;
83
105
  private rtpTimestamp = 0;
84
106
  private octetCount = 0;
@@ -233,8 +255,8 @@ export class RTCRtpSender {
233
255
  }),
234
256
  }),
235
257
  ];
236
- this.lsr = compactNtp(this.ntpTimestamp);
237
- this.lsrTime = Date.now() / 1000;
258
+ this.lastSRtimestamp = compactNtp(this.ntpTimestamp);
259
+ this.lastSentSRTimestamp = timestampSeconds();
238
260
 
239
261
  if (this.cname) {
240
262
  packets.push(
@@ -375,13 +397,17 @@ export class RTCRtpSender {
375
397
  packet.reports
376
398
  .filter((report) => report.ssrc === this.ssrc)
377
399
  .forEach((report) => {
378
- if (this.lsr === report.lsr && report.dlsr) {
379
- const rtt =
380
- Date.now() / 1000 - this.lsrTime - report.dlsr / 65536;
381
- if (this.rtt === undefined) {
382
- this.rtt = rtt;
383
- } else {
384
- this.rtt = RTT_ALPHA * this.rtt + (1 - RTT_ALPHA) * rtt;
400
+ if (this.lastSRtimestamp === report.lsr && report.dlsr) {
401
+ if (this.lastSentSRTimestamp) {
402
+ const rtt =
403
+ timestampSeconds() -
404
+ this.lastSentSRTimestamp -
405
+ report.dlsr / 65536;
406
+ if (this.rtt === undefined) {
407
+ this.rtt = rtt;
408
+ } else {
409
+ this.rtt = RTT_ALPHA * this.rtt + (1 - RTT_ALPHA) * rtt;
410
+ }
385
411
  }
386
412
  }
387
413
  });
@@ -14,7 +14,7 @@ import { MediaStreamTrack } from "./track";
14
14
 
15
15
  export class RTCRtpTransceiver {
16
16
  readonly uuid = uuid.v4();
17
- readonly onTrack = new Event<[MediaStreamTrack]>();
17
+ readonly onTrack = new Event<[MediaStreamTrack, RTCRtpTransceiver]>();
18
18
  mid?: string;
19
19
  mLineIndex?: number;
20
20
  usedForSender = false;
@@ -69,7 +69,9 @@ export class RTCRtpTransceiver {
69
69
 
70
70
  addTrack(track: MediaStreamTrack) {
71
71
  const res = this.receiver.addTrack(track);
72
- if (res) this.onTrack.execute(track);
72
+ if (res) {
73
+ this.onTrack.execute(track, this);
74
+ }
73
75
  }
74
76
 
75
77
  // todo impl
@@ -89,12 +91,12 @@ export class RTCRtpTransceiver {
89
91
  }
90
92
  }
91
93
 
92
- export const Directions = [
93
- "inactive",
94
- "sendonly",
95
- "recvonly",
96
- "sendrecv",
97
- ] as const;
94
+ export const Inactive = "inactive";
95
+ export const Sendonly = "sendonly";
96
+ export const Recvonly = "recvonly";
97
+ export const Sendrecv = "sendrecv";
98
+
99
+ export const Directions = [Inactive, Sendonly, Recvonly, Sendrecv] as const;
98
100
 
99
101
  export type Direction = typeof Directions[number];
100
102
 
@@ -52,8 +52,12 @@ export class MediaStreamTrack extends EventTarget {
52
52
  };
53
53
 
54
54
  writeRtp = (rtp: RtpPacket | Buffer) => {
55
- if (this.remote) throw new Error("this is remoteTrack");
56
- if (!this.codec || this.stopped) return;
55
+ if (this.remote) {
56
+ throw new Error("this is remoteTrack");
57
+ }
58
+ if (!this.codec || this.stopped) {
59
+ return;
60
+ }
57
61
 
58
62
  const packet = Buffer.isBuffer(rtp) ? RtpPacket.deSerialize(rtp) : rtp;
59
63
  packet.header.payloadType = this.codec.payloadType;
@@ -26,8 +26,8 @@ export class MediaRecorder {
26
26
  this.tracks.push(track);
27
27
  }
28
28
 
29
- start() {
30
- this.writer.start(this.tracks);
29
+ async start() {
30
+ await this.writer.start(this.tracks);
31
31
  }
32
32
 
33
33
  async stop() {
@@ -38,4 +38,8 @@ export class MediaRecorder {
38
38
  export interface MediaRecorderOptions {
39
39
  width: number;
40
40
  height: number;
41
+ jitterBufferLatency: number;
42
+ jitterBufferSize: number;
43
+ waitForKeyframe: boolean;
44
+ defaultDuration: number;
41
45
  }
@@ -7,7 +7,7 @@ export abstract class MediaWriter {
7
7
  protected options: Partial<MediaRecorderOptions>
8
8
  ) {}
9
9
 
10
- start(tracks: MediaStreamTrack[]) {}
10
+ async start(tracks: MediaStreamTrack[]) {}
11
11
 
12
12
  async stop() {}
13
13
  }