@livedigital/client 2.7.0 → 2.7.2-improve-network-issue-detector.1
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/dist/index.es.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/engine/wid/WebRTCIssueDetector.ts +4 -0
- package/src/engine/wid/detectors/FramesDroppedIssueDetector.ts +4 -0
- package/src/engine/wid/detectors/FramesEncodedSentIssueDetector.ts +4 -0
- package/src/engine/wid/detectors/NetworkIssueDetector.ts +34 -11
- package/src/engine/wid/detectors/QualityLimitationsIssueDetector.ts +4 -0
package/package.json
CHANGED
|
@@ -18,6 +18,10 @@ class FramesDroppedIssueDetector implements IssueDetector {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
private processData(data: WebRTCStatsEventData): IssueDetectorResult {
|
|
21
|
+
if (!data.video?.inbound) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
const streamsWithDroppedFrames = data.video.inbound.filter((stats) => stats.framesDropped > 0);
|
|
22
26
|
const issues: IssueDetectorResult = [];
|
|
23
27
|
const previousInboundRTPVideoStreamsStats = this.#lastProcessedStats[data.connection.id]?.video.inbound;
|
|
@@ -18,6 +18,10 @@ class FramesEncodedSentIssueDetector implements IssueDetector {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
private processData(data: WebRTCStatsEventData): IssueDetectorResult {
|
|
21
|
+
if (!data.video?.outbound) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
const streamsWithEncodedFrames = data.video.outbound.filter((stats) => stats.framesEncoded > 0);
|
|
22
26
|
const issues: IssueDetectorResult = [];
|
|
23
27
|
const previousOutboundRTPVideoStreamsStats = this.#lastProcessedStats[data.connection.id]?.video.outbound;
|
|
@@ -17,9 +17,9 @@ class NetworkIssueDetector implements IssueDetector {
|
|
|
17
17
|
|
|
18
18
|
private processData(data: WebRTCStatsEventData): IssueDetectorResult {
|
|
19
19
|
const issues: IssueDetectorResult = [];
|
|
20
|
-
const inboundRTPStreamsStats = [...data.audio
|
|
20
|
+
const inboundRTPStreamsStats = [...data.audio?.inbound, ...data.video?.inbound];
|
|
21
21
|
const previousStats = this.#lastProcessedStats[data.connection.id];
|
|
22
|
-
const previousInboundStreamStats = [...previousStats.video
|
|
22
|
+
const previousInboundStreamStats = [...previousStats.video?.inbound, ...previousStats.audio?.inbound];
|
|
23
23
|
|
|
24
24
|
if (!inboundRTPStreamsStats.length || !previousStats) {
|
|
25
25
|
return issues;
|
|
@@ -30,21 +30,30 @@ class NetworkIssueDetector implements IssueDetector {
|
|
|
30
30
|
|
|
31
31
|
const rtpNetworkStats = inboundRTPStreamsStats.reduce((stats, currentStreamStats) => {
|
|
32
32
|
const previousStreamStats = previousInboundStreamStats.find((stream) => stream.ssrc === currentStreamStats.ssrc);
|
|
33
|
+
|
|
33
34
|
const lastJitterBufferDelay = previousStreamStats?.jitterBufferDelay || 0;
|
|
34
35
|
const lastJitterBufferEmittedCount = previousStreamStats?.jitterBufferEmittedCount || 0;
|
|
35
36
|
const delay = currentStreamStats.jitterBufferDelay - lastJitterBufferDelay;
|
|
36
37
|
const emitted = currentStreamStats.jitterBufferEmittedCount - lastJitterBufferEmittedCount;
|
|
37
|
-
const
|
|
38
|
+
const jitterBufferDelayMs = delay && emitted ? (1e3 * delay) / emitted : 0;
|
|
38
39
|
|
|
39
40
|
return {
|
|
40
|
-
|
|
41
|
+
sumJitter: stats.sumJitter + currentStreamStats.jitter,
|
|
42
|
+
sumJitterBufferDelayMs: stats.sumJitterBufferDelayMs + jitterBufferDelayMs,
|
|
41
43
|
packetsLost: stats.packetsLost + currentStreamStats.packetsLost,
|
|
42
44
|
lastPacketsLost: stats.lastPacketsLost + (previousStreamStats?.packetsLost || 0),
|
|
43
45
|
};
|
|
44
|
-
}, {
|
|
46
|
+
}, {
|
|
47
|
+
sumJitter: 0,
|
|
48
|
+
sumJitterBufferDelayMs: 0,
|
|
49
|
+
packetsLost: 0,
|
|
50
|
+
lastPacketsLost: 0,
|
|
51
|
+
});
|
|
45
52
|
|
|
46
53
|
const rtt = (1e3 * data.connection.currentRoundTripTime) || 0;
|
|
47
|
-
const
|
|
54
|
+
const { sumJitter, sumJitterBufferDelayMs } = rtpNetworkStats;
|
|
55
|
+
const avgJitter = sumJitter / inboundRTPStreamsStats.length;
|
|
56
|
+
const avgJitterBufferDelay = sumJitterBufferDelayMs / inboundRTPStreamsStats.length;
|
|
48
57
|
|
|
49
58
|
const deltaPacketReceived = packetsReceived - lastPacketsReceived;
|
|
50
59
|
const deltaPacketLost = rtpNetworkStats.packetsLost - rtpNetworkStats.lastPacketsLost;
|
|
@@ -54,19 +63,24 @@ class NetworkIssueDetector implements IssueDetector {
|
|
|
54
63
|
: 0;
|
|
55
64
|
|
|
56
65
|
const isHighPacketsLoss = packetsLoss > 5;
|
|
57
|
-
const isHighJitter =
|
|
58
|
-
const isHighRTT = rtt >=
|
|
66
|
+
const isHighJitter = avgJitter >= 200;
|
|
67
|
+
const isHighRTT = rtt >= 250;
|
|
68
|
+
const isHighJitterBufferDelay = avgJitterBufferDelay > 500;
|
|
59
69
|
|
|
60
70
|
const isNetworkIssue = (!isHighPacketsLoss && isHighJitter) || isHighJitter || isHighPacketsLoss;
|
|
61
71
|
const isServerIssue = isHighRTT && !isHighJitter && !isHighPacketsLoss;
|
|
62
72
|
const isNetworkMediaLatencyIssue = isHighPacketsLoss && isHighJitter;
|
|
73
|
+
const isNetworkMediaSyncIssue = isHighJitter && isHighJitterBufferDelay;
|
|
74
|
+
|
|
75
|
+
const debug = `packetLoss: ${packetsLoss}%, jitter: ${avgJitter}, rtt: ${rtt},`
|
|
76
|
+
+ ` jitterBuffer: ${avgJitterBufferDelay}ms`;
|
|
63
77
|
|
|
64
78
|
if (isNetworkIssue) {
|
|
65
79
|
issues.push({
|
|
66
80
|
type: IssueType.Network,
|
|
67
81
|
reason: IssueReason.NetworkQuality,
|
|
68
82
|
iceCandidate: data.connection.local.id,
|
|
69
|
-
debug
|
|
83
|
+
debug,
|
|
70
84
|
});
|
|
71
85
|
}
|
|
72
86
|
|
|
@@ -75,7 +89,7 @@ class NetworkIssueDetector implements IssueDetector {
|
|
|
75
89
|
type: IssueType.Server,
|
|
76
90
|
reason: IssueReason.ServerIssue,
|
|
77
91
|
iceCandidate: data.connection.remote.id,
|
|
78
|
-
debug
|
|
92
|
+
debug,
|
|
79
93
|
});
|
|
80
94
|
}
|
|
81
95
|
|
|
@@ -84,7 +98,16 @@ class NetworkIssueDetector implements IssueDetector {
|
|
|
84
98
|
type: IssueType.Network,
|
|
85
99
|
reason: IssueReason.NetworkMediaLatency,
|
|
86
100
|
iceCandidate: data.connection.local.id,
|
|
87
|
-
debug
|
|
101
|
+
debug,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (isNetworkMediaSyncIssue) {
|
|
106
|
+
issues.push({
|
|
107
|
+
type: IssueType.Network,
|
|
108
|
+
reason: IssueReason.NetworkMediaSyncFailure,
|
|
109
|
+
iceCandidate: data.connection.local.id,
|
|
110
|
+
debug,
|
|
88
111
|
});
|
|
89
112
|
}
|
|
90
113
|
|
|
@@ -16,6 +16,10 @@ class QualityLimitationsIssueDetector implements IssueDetector {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
private processData(data: WebRTCStatsEventData): IssueDetectorResult {
|
|
19
|
+
if (!data.video?.outbound) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
const streamsWithLimitation = data.video.outbound.filter((stats) => stats.qualityLimitationReason !== 'none');
|
|
20
24
|
const issues: IssueDetectorResult = [];
|
|
21
25
|
const previousOutboundRTPVideoStreamsStats = this.#lastProcessedStats[data.connection.id]?.video.outbound;
|