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.
- package/lib/common/src/index.d.ts +2 -0
- package/lib/common/src/index.js +2 -0
- package/lib/common/src/index.js.map +1 -1
- package/lib/common/src/log.d.ts +11 -0
- package/lib/common/src/log.js +17 -0
- package/lib/common/src/log.js.map +1 -0
- package/lib/common/src/network.d.ts +7 -3
- package/lib/common/src/network.js +15 -7
- package/lib/common/src/network.js.map +1 -1
- package/lib/common/src/type.d.ts +3 -0
- package/lib/common/src/type.js +3 -0
- package/lib/common/src/type.js.map +1 -0
- package/lib/dtls/src/context/cipher.js.map +1 -1
- package/lib/dtls/src/flight/server/flight2.js +10 -0
- package/lib/dtls/src/flight/server/flight2.js.map +1 -1
- package/lib/ice/src/ice.d.ts +3 -0
- package/lib/ice/src/ice.js +9 -2
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/stun/protocol.d.ts +2 -1
- package/lib/ice/src/stun/protocol.js +3 -3
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/transport.d.ts +4 -2
- package/lib/ice/src/transport.js +8 -6
- package/lib/ice/src/transport.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +3 -1
- package/lib/ice/src/turn/protocol.js +2 -2
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/utils.d.ts +2 -1
- package/lib/ice/src/utils.js +2 -2
- package/lib/ice/src/utils.js.map +1 -1
- package/lib/rtp/src/codec/index.d.ts +18 -0
- package/lib/rtp/src/codec/index.js +81 -0
- package/lib/rtp/src/codec/index.js.map +1 -0
- package/lib/rtp/src/codec/vp8.d.ts +5 -3
- package/lib/rtp/src/codec/vp8.js +19 -5
- package/lib/rtp/src/codec/vp8.js.map +1 -1
- package/lib/rtp/src/container/webm.d.ts +6 -1
- package/lib/rtp/src/container/webm.js +9 -2
- package/lib/rtp/src/container/webm.js.map +1 -1
- package/lib/rtp/src/index.d.ts +2 -6
- package/lib/rtp/src/index.js +2 -6
- package/lib/rtp/src/index.js.map +1 -1
- package/lib/rtp/src/processor/base.d.ts +3 -1
- package/lib/rtp/src/processor/base.js +19 -6
- package/lib/rtp/src/processor/base.js.map +1 -1
- package/lib/rtp/src/processor/jitterBuffer.js +1 -2
- package/lib/rtp/src/processor/jitterBuffer.js.map +1 -1
- package/lib/rtp/src/processor/lipsync.js +22 -2
- package/lib/rtp/src/processor/lipsync.js.map +1 -1
- package/lib/rtp/src/processor/webm.d.ts +11 -7
- package/lib/rtp/src/processor/webm.js +16 -41
- package/lib/rtp/src/processor/webm.js.map +1 -1
- package/lib/rtp/src/processor_v2/depacketizer.d.ts +17 -0
- package/lib/rtp/src/processor_v2/depacketizer.js +84 -0
- package/lib/rtp/src/processor_v2/depacketizer.js.map +1 -0
- package/lib/rtp/src/processor_v2/index.d.ts +4 -0
- package/lib/rtp/src/processor_v2/index.js +21 -0
- package/lib/rtp/src/processor_v2/index.js.map +1 -0
- package/lib/rtp/src/processor_v2/jitterBuffer.d.ts +33 -0
- package/lib/rtp/src/processor_v2/jitterBuffer.js +154 -0
- package/lib/rtp/src/processor_v2/jitterBuffer.js.map +1 -0
- package/lib/rtp/src/processor_v2/source/base.d.ts +8 -0
- package/lib/rtp/src/processor_v2/source/base.js +16 -0
- package/lib/rtp/src/processor_v2/source/base.js.map +1 -0
- package/lib/rtp/src/processor_v2/source/index.d.ts +2 -0
- package/lib/rtp/src/processor_v2/source/index.js +6 -0
- package/lib/rtp/src/processor_v2/source/index.js.map +1 -0
- package/lib/rtp/src/processor_v2/source/rtp.d.ts +14 -0
- package/lib/rtp/src/processor_v2/source/rtp.js +24 -0
- package/lib/rtp/src/processor_v2/source/rtp.js.map +1 -0
- package/lib/rtp/src/processor_v2/webmLive.d.ts +51 -0
- package/lib/rtp/src/processor_v2/webmLive.js +154 -0
- package/lib/rtp/src/processor_v2/webmLive.js.map +1 -0
- package/lib/rtp/src/rtcp/header.d.ts +2 -1
- package/lib/rtp/src/rtcp/header.js +3 -2
- package/lib/rtp/src/rtcp/header.js.map +1 -1
- package/lib/rtp/src/rtcp/rr.d.ts +2 -0
- package/lib/rtp/src/rtcp/rr.js.map +1 -1
- package/lib/rtp/src/rtcp/rtcp.js +4 -4
- package/lib/rtp/src/rtcp/rtcp.js.map +1 -1
- package/lib/rtp/src/rtcp/rtpfb/index.js +1 -1
- package/lib/rtp/src/rtcp/rtpfb/index.js.map +1 -1
- package/lib/rtp/src/rtcp/rtpfb/nack.js +15 -7
- package/lib/rtp/src/rtcp/rtpfb/nack.js.map +1 -1
- package/lib/rtp/src/rtp/red/packet.d.ts +1 -0
- package/lib/rtp/src/rtp/red/packet.js.map +1 -1
- package/lib/rtp/src/rtp/rtp.d.ts +1 -0
- package/lib/rtp/src/rtp/rtp.js +27 -26
- package/lib/rtp/src/rtp/rtp.js.map +1 -1
- package/lib/rtp/src/srtp/cipher/ctr.d.ts +1 -1
- package/lib/rtp/src/srtp/cipher/ctr.js +14 -20
- package/lib/rtp/src/srtp/cipher/ctr.js.map +1 -1
- package/lib/webrtc/src/dataChannel.js +1 -1
- package/lib/webrtc/src/dataChannel.js.map +1 -1
- package/lib/webrtc/src/media/extension/rtpExtension.d.ts +2 -0
- package/lib/webrtc/src/media/extension/rtpExtension.js +8 -1
- package/lib/webrtc/src/media/extension/rtpExtension.js.map +1 -1
- package/lib/webrtc/src/media/parameters.d.ts +2 -0
- package/lib/webrtc/src/media/parameters.js +1 -0
- package/lib/webrtc/src/media/parameters.js.map +1 -1
- package/lib/webrtc/src/media/receiver/nack.d.ts +10 -5
- package/lib/webrtc/src/media/receiver/nack.js +44 -27
- package/lib/webrtc/src/media/receiver/nack.js.map +1 -1
- package/lib/webrtc/src/media/receiver/receiverTwcc.js +1 -1
- package/lib/webrtc/src/media/receiver/receiverTwcc.js.map +1 -1
- package/lib/webrtc/src/media/receiver/red.d.ts +1 -1
- package/lib/webrtc/src/media/receiver/red.js +14 -3
- package/lib/webrtc/src/media/receiver/red.js.map +1 -1
- package/lib/webrtc/src/media/router.d.ts +10 -3
- package/lib/webrtc/src/media/router.js +2 -0
- package/lib/webrtc/src/media/router.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +11 -3
- package/lib/webrtc/src/media/rtpReceiver.js +42 -23
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.d.ts +23 -2
- package/lib/webrtc/src/media/rtpSender.js +34 -10
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/media/rtpTransceiver.d.ts +5 -1
- package/lib/webrtc/src/media/rtpTransceiver.js +9 -9
- package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
- package/lib/webrtc/src/media/track.js +4 -2
- package/lib/webrtc/src/media/track.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/index.d.ts +5 -1
- package/lib/webrtc/src/nonstandard/recorder/index.js +2 -2
- package/lib/webrtc/src/nonstandard/recorder/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/index.d.ts +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/index.js +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.d.ts +3 -3
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +61 -41
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +13 -0
- package/lib/webrtc/src/peerConnection.js +40 -3
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/sdp.d.ts +1 -0
- package/lib/webrtc/src/sdp.js +4 -0
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/transport/dtls.js +6 -1
- package/lib/webrtc/src/transport/dtls.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.js +1 -1
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/lib/webrtc/src/utils.d.ts +7 -2
- package/lib/webrtc/src/utils.js +9 -3
- package/lib/webrtc/src/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/dataChannel.ts +1 -1
- package/src/media/extension/rtpExtension.ts +8 -0
- package/src/media/parameters.ts +3 -0
- package/src/media/receiver/nack.ts +45 -26
- package/src/media/receiver/receiverTwcc.ts +1 -1
- package/src/media/receiver/red.ts +14 -1
- package/src/media/router.ts +5 -3
- package/src/media/rtpReceiver.ts +59 -28
- package/src/media/rtpSender.ts +38 -12
- package/src/media/rtpTransceiver.ts +10 -8
- package/src/media/track.ts +6 -2
- package/src/nonstandard/recorder/index.ts +6 -2
- package/src/nonstandard/recorder/writer/index.ts +1 -1
- package/src/nonstandard/recorder/writer/webm.ts +105 -57
- package/src/peerConnection.ts +61 -7
- package/src/sdp.ts +3 -0
- package/src/transport/dtls.ts +5 -1
- package/src/transport/sctp.ts +1 -1
- 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
|
|
17
|
+
export class NackHandler {
|
|
15
18
|
private newEstSeqNum = 0;
|
|
16
|
-
|
|
17
|
-
private nackLoop = setInterval(() => this.
|
|
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
|
|
25
|
-
return Object.keys(this.
|
|
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.
|
|
38
|
-
|
|
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.
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
69
|
-
Object.keys(this.
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
77
|
-
if (this.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
}
|
package/src/media/router.ts
CHANGED
|
@@ -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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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) => {
|
package/src/media/rtpReceiver.ts
CHANGED
|
@@ -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 {
|
|
25
|
+
import { NackHandler } from "./receiver/nack";
|
|
26
26
|
import { ReceiverTWCC } from "./receiver/receiverTwcc";
|
|
27
|
-
import {
|
|
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
|
|
38
|
-
private readonly redHandler = new
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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(
|
|
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
|
|
140
|
-
|
|
141
|
-
if (this.
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
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.
|
|
196
|
-
|
|
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
|
-
|
|
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
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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.
|
|
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.
|
|
329
|
+
rtx.payload.subarray(2)
|
|
299
330
|
);
|
|
300
331
|
return packet;
|
|
301
332
|
}
|
package/src/media/rtpSender.ts
CHANGED
|
@@ -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
|
|
81
|
-
private
|
|
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.
|
|
237
|
-
this.
|
|
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.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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)
|
|
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
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
|
package/src/media/track.ts
CHANGED
|
@@ -52,8 +52,12 @@ export class MediaStreamTrack extends EventTarget {
|
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
writeRtp = (rtp: RtpPacket | Buffer) => {
|
|
55
|
-
if (this.remote)
|
|
56
|
-
|
|
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
|
}
|