@livedigital/client 2.26.0-stop-streams.2 → 2.26.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 (48) hide show
  1. package/dist/engine/DefaultEngineDependenciesFactory.d.ts +1 -1
  2. package/dist/engine/index.d.ts +0 -1
  3. package/dist/engine/media/tracks/BaseTrack.d.ts +0 -3
  4. package/dist/index.es.js +1 -1
  5. package/dist/index.js +2 -2
  6. package/dist/types/common.d.ts +0 -4
  7. package/dist/types/engine.d.ts +1 -2
  8. package/package.json +3 -2
  9. package/src/engine/DefaultEngineDependenciesFactory.ts +15 -14
  10. package/src/engine/index.ts +19 -22
  11. package/src/engine/media/index.ts +9 -16
  12. package/src/engine/media/tracks/BaseTrack.ts +5 -22
  13. package/src/types/common.ts +0 -5
  14. package/src/types/engine.ts +1 -2
  15. package/dist/engine/media/tracks/MediaStreamTrackManager.d.ts +0 -14
  16. package/dist/engine/wid/WebRTCIssueDetector.d.ts +0 -20
  17. package/dist/engine/wid/WebRTCIssueEmitter.d.ts +0 -11
  18. package/dist/engine/wid/detectors/AvailableOutgoingBitrateIssueDetector.d.ts +0 -6
  19. package/dist/engine/wid/detectors/FramesDroppedIssueDetector.d.ts +0 -7
  20. package/dist/engine/wid/detectors/FramesEncodedSentIssueDetector.d.ts +0 -7
  21. package/dist/engine/wid/detectors/InboundNetworkIssueDetector.d.ts +0 -7
  22. package/dist/engine/wid/detectors/NetworkMediaSyncIssueDetector.d.ts +0 -7
  23. package/dist/engine/wid/detectors/OutboundNetworkIssueDetector.d.ts +0 -7
  24. package/dist/engine/wid/detectors/QualityLimitationsIssueDetector.d.ts +0 -7
  25. package/dist/engine/wid/detectors/VideoCodecMismatchDetector.d.ts +0 -10
  26. package/dist/engine/wid/lib/NetworkScoresCalculator.d.ts +0 -9
  27. package/dist/engine/wid/lib/PeriodicWebRTCStatsReporter.d.ts +0 -20
  28. package/dist/engine/wid/lib/parser/CompositeRTCStatsParser.d.ts +0 -22
  29. package/dist/engine/wid/lib/parser/RTCStatsParser.d.ts +0 -20
  30. package/dist/engine/wid/lib/parser/utils.d.ts +0 -7
  31. package/dist/engine/wid/types.d.ts +0 -381
  32. package/src/engine/media/tracks/MediaStreamTrackManager.ts +0 -46
  33. package/src/engine/wid/WebRTCIssueDetector.ts +0 -136
  34. package/src/engine/wid/WebRTCIssueEmitter.ts +0 -16
  35. package/src/engine/wid/detectors/AvailableOutgoingBitrateIssueDetector.ts +0 -57
  36. package/src/engine/wid/detectors/FramesDroppedIssueDetector.ts +0 -65
  37. package/src/engine/wid/detectors/FramesEncodedSentIssueDetector.ts +0 -69
  38. package/src/engine/wid/detectors/InboundNetworkIssueDetector.ts +0 -120
  39. package/src/engine/wid/detectors/NetworkMediaSyncIssueDetector.ts +0 -60
  40. package/src/engine/wid/detectors/OutboundNetworkIssueDetector.ts +0 -96
  41. package/src/engine/wid/detectors/QualityLimitationsIssueDetector.ts +0 -63
  42. package/src/engine/wid/detectors/VideoCodecMismatchDetector.ts +0 -78
  43. package/src/engine/wid/lib/NetworkScoresCalculator.ts +0 -126
  44. package/src/engine/wid/lib/PeriodicWebRTCStatsReporter.ts +0 -66
  45. package/src/engine/wid/lib/parser/CompositeRTCStatsParser.ts +0 -82
  46. package/src/engine/wid/lib/parser/RTCStatsParser.ts +0 -274
  47. package/src/engine/wid/lib/parser/utils.ts +0 -40
  48. package/src/engine/wid/types.ts +0 -408
@@ -1,381 +0,0 @@
1
- import { Logger } from '../../types/common';
2
- import PeriodicWebRTCStatsReporter from './lib/PeriodicWebRTCStatsReporter';
3
- import { AddConnectionPayload } from './lib/parser/CompositeRTCStatsParser';
4
- import { WebRTCIssueEmitter } from './WebRTCIssueEmitter';
5
- export interface WIDWindow {
6
- wid: {
7
- handleNewPeerConnection(pc: RTCPeerConnection): void;
8
- };
9
- }
10
- export declare type IssueDetectorResult = IssuePayload[];
11
- export interface IssueDetector {
12
- detect(data: WebRTCStatsParsed): IssueDetectorResult;
13
- }
14
- export interface NetworkScoresCalculator {
15
- calculate(data: WebRTCStatsParsed): NetworkScores;
16
- }
17
- export declare enum EventType {
18
- Issue = "issue",
19
- NetworkScoresUpdated = "network-scores-updated"
20
- }
21
- export declare type EventPayload = IssueDetectorResult;
22
- export interface StatsReportItem {
23
- id: string;
24
- stats: WebRTCStatsParsed;
25
- timeTaken: number;
26
- }
27
- export interface ConnectionInfo {
28
- id: string;
29
- pc: RTCPeerConnection;
30
- }
31
- export interface CompositeStatsParser {
32
- addPeerConnection: (payload: AddConnectionPayload) => void;
33
- parse: () => Promise<StatsReportItem[]>;
34
- }
35
- export interface StatsParser {
36
- parse: (info: ConnectionInfo) => Promise<StatsReportItem | undefined>;
37
- }
38
- export declare type WebRTCIssueDetectorConstructorParams = {
39
- issueEmitter: WebRTCIssueEmitter;
40
- networkScoresCalculator: NetworkScoresCalculator;
41
- detectors: IssueDetector[];
42
- compositeStatsParser: CompositeStatsParser;
43
- statsReporter: PeriodicWebRTCStatsReporter;
44
- logger: Logger;
45
- onIssues?: (payload: IssueDetectorResult) => void;
46
- onNetworkScoresUpdated?: (payload: NetworkScores) => void;
47
- ignoreSSRCList?: number[];
48
- getStatsInterval?: number;
49
- };
50
- export declare enum IssueType {
51
- Network = "network",
52
- CPU = "cpu",
53
- Server = "server",
54
- Stream = "stream"
55
- }
56
- export declare enum IssueReason {
57
- OutboundNetworkQuality = "outbound-network-quality",
58
- InboundNetworkQuality = "inbound-network-quality",
59
- OutboundNetworkMediaLatency = "outbound-network-media-latency",
60
- InboundNetworkMediaLatency = "inbound-network-media-latency",
61
- NetworkMediaSyncFailure = "network-media-sync-failure",
62
- OutboundNetworkThroughput = "outbound-network-throughput",
63
- InboundNetworkThroughput = "inbound-network-throughput",
64
- EncoderCPUThrottling = "encoder-cpu-throttling",
65
- DecoderCPUThrottling = "decoder-cpu-throttling",
66
- ServerIssue = "server-issue",
67
- VideoCodecMismatchIssue = "codec-mismatch",
68
- LowInboundMOS = "low-inbound-mean-opinion-score",
69
- LowOutboundMOS = "low-outbound-mean-opinion-score"
70
- }
71
- export declare type IssuePayload = {
72
- type: IssueType;
73
- reason: IssueReason;
74
- ssrc?: number;
75
- iceCandidate?: string;
76
- data?: number;
77
- debug?: string;
78
- trackIdentifier?: string;
79
- };
80
- export declare type DetectIssuesPayload = {
81
- data: WebRTCStatsParsed;
82
- ignoreSSRCList?: number[];
83
- };
84
- export declare type NetworkScore = number;
85
- export declare type NetworkScores = {
86
- outbound?: NetworkScore;
87
- inbound?: NetworkScore;
88
- };
89
- export declare type ParsedInboundAudioStreamStats = {
90
- audioLevel: number;
91
- bitrate: number;
92
- bytesReceived: number;
93
- clockRate: number;
94
- codecId: string;
95
- concealedSamples: number;
96
- concealmentEvents: number;
97
- fecPacketsDiscarded: number;
98
- fecPacketsReceived: number;
99
- headerBytesReceived: number;
100
- id: string;
101
- insertedSamplesForDeceleration: number;
102
- jitter: number;
103
- jitterBufferDelay: number;
104
- jitterBufferEmittedCount: number;
105
- kind: 'audio';
106
- lastPacketReceivedTimestamp: number;
107
- mediaType: string;
108
- mimeType: string;
109
- packetRate: number;
110
- packetsDiscarded: number;
111
- packetsLost: number;
112
- packetsReceived: number;
113
- payloadType: number;
114
- remoteId: string;
115
- removedSamplesForAcceleration: number;
116
- silentConcealedSamples: number;
117
- ssrc: number;
118
- timestamp: number;
119
- totalAudioEnergy: number;
120
- totalSamplesDuration: number;
121
- totalSamplesReceived: number;
122
- track: {
123
- audioLevel: number;
124
- concealedSamples: number;
125
- concealmentEvents: number;
126
- detached: boolean;
127
- ended: boolean;
128
- id: string;
129
- insertedSamplesForDeceleration: number;
130
- jitterBufferDelay: number;
131
- jitterBufferEmittedCount: number;
132
- kind: 'audio';
133
- remoteSource: boolean;
134
- removedSamplesForAcceleration: number;
135
- silentConcealedSamples: number;
136
- timestamp: number;
137
- totalAudioEnergy: number;
138
- totalSamplesDuration: number;
139
- totalSamplesReceived: number;
140
- trackIdentifier: string;
141
- type: string;
142
- };
143
- trackId: string;
144
- transportId: string;
145
- };
146
- export declare type ParsedOutboundAudioStreamStats = {
147
- bitrate: number;
148
- bytesSent: number;
149
- clockRate: number;
150
- codecId: string;
151
- headerBytesSent: number;
152
- id: string;
153
- kind: string;
154
- mediaSourceId: string;
155
- mediaType: string;
156
- mimeType: string;
157
- nackCount: number;
158
- packetRate: number;
159
- packetsSent: number;
160
- payloadType: number;
161
- remoteId: string;
162
- retransmittedBytesSent: number;
163
- retransmittedPacketsSent: number;
164
- ssrc: number;
165
- timestamp: number;
166
- targetBitrate: number;
167
- track: {
168
- audioLevel: number;
169
- echoReturnLoss: number;
170
- echoReturnLossEnhancement: number;
171
- id: string;
172
- kind: string;
173
- timestamp: number;
174
- totalAudioEnergy: number;
175
- totalSamplesDuration: number;
176
- trackIdentifier: string;
177
- type: string;
178
- };
179
- trackId: string;
180
- transportId: string;
181
- };
182
- export declare type ParsedInboundVideoStreamStats = {
183
- bitrate: number;
184
- bytesReceived: number;
185
- clockRate: number;
186
- codecId: string;
187
- decoderImplementation: string;
188
- firCount: number;
189
- frameHeight: number;
190
- frameWidth: number;
191
- framesDecoded: number;
192
- framesDropped: number;
193
- framesPerSecond: number;
194
- framesReceived: number;
195
- headerBytesReceived: number;
196
- id: string;
197
- jitter: number;
198
- jitterBufferDelay: number;
199
- jitterBufferEmittedCount: number;
200
- keyFramesDecoded: number;
201
- kind: 'video';
202
- mediaType: string;
203
- mimeType: string;
204
- nackCount: number;
205
- packetRate: number;
206
- packetsLost: number;
207
- packetsReceived: number;
208
- payloadType: number;
209
- pliCount: number;
210
- ssrc: number;
211
- timestamp: number;
212
- totalDecodeTime: number;
213
- totalInterFrameDelay: number;
214
- totalSquaredInterFrameDelay: number;
215
- track: {
216
- detached: boolean;
217
- ended: boolean;
218
- frameHeight: number;
219
- frameWidth: number;
220
- framesDecoded: number;
221
- framesDropped: number;
222
- framesReceived: number;
223
- id: string;
224
- jitterBufferDelay: number;
225
- jitterBufferEmittedCount: number;
226
- kind: 'video';
227
- remoteSource: boolean;
228
- timestamp: number;
229
- trackIdentifier: string;
230
- type: string;
231
- };
232
- trackId: string;
233
- transportId: string;
234
- };
235
- export declare type ParsedOutboundVideoStreamStats = {
236
- bitrate: number;
237
- bytesSent: number;
238
- clockRate: number;
239
- codecId: string;
240
- encoderImplementation: string;
241
- firCount: number;
242
- frameHeight: number;
243
- frameWidth: number;
244
- framesEncoded: number;
245
- framesPerSecond: number;
246
- framesSent: number;
247
- headerBytesSent: number;
248
- hugeFramesSent: number;
249
- id: string;
250
- keyFramesEncoded: number;
251
- kind: string;
252
- mediaSourceId: string;
253
- mediaType: string;
254
- mimeType: string;
255
- nackCount: number;
256
- packetRate: number;
257
- packetsSent: number;
258
- payloadType: number;
259
- pliCount: number;
260
- qpSum: number;
261
- qualityLimitationDurations: {
262
- other: number;
263
- cpu: number;
264
- bandwidth: number;
265
- none: number;
266
- };
267
- qualityLimitationReason: 'none' | 'bandwidth' | 'cpu' | 'other';
268
- qualityLimitationResolutionChanges: number;
269
- remoteId: string;
270
- retransmittedBytesSent: number;
271
- retransmittedPacketsSent: number;
272
- rid: string;
273
- ssrc: number;
274
- timestamp: number;
275
- totalEncodeTime: number;
276
- totalEncodedBytesTarget: number;
277
- totalPacketSendDelay: number;
278
- track: {
279
- id: string;
280
- frames: number;
281
- framesPerSecond: number;
282
- height: number;
283
- timestamp: number;
284
- type: string;
285
- trackIdentifier: string;
286
- kind: string;
287
- width: number;
288
- };
289
- trackId: string;
290
- transportId: string;
291
- type: string;
292
- };
293
- export declare type ParsedConnectionStats = {
294
- availableOutgoingBitrate: number;
295
- bytesReceived: number;
296
- bytesSent: number;
297
- currentRoundTripTime: number;
298
- id: string;
299
- transportId: string;
300
- packetsReceived: number;
301
- packetsSent: number;
302
- state: string;
303
- totalRoundTripTime: number;
304
- type: string;
305
- local: IceCandidateConnectionStats;
306
- remote: IceCandidateConnectionStats;
307
- };
308
- export declare type IceCandidateConnectionStats = {
309
- address: string;
310
- candidateType: string;
311
- id: string;
312
- ip: string;
313
- isRemote: boolean;
314
- networkType?: string;
315
- port: number;
316
- priority: number;
317
- protocol: 'udp' | 'tcp';
318
- timestamp: number;
319
- transportId: string;
320
- type: 'local-candidate' | 'remote-candidate';
321
- };
322
- export declare type ParsedRemoteInboundStreamStats = {
323
- clockRate: number;
324
- codecId: string;
325
- fractionLost: number;
326
- id: string;
327
- jitter: number;
328
- kind: string;
329
- localId: string;
330
- mimeType: string;
331
- packetsLost: number;
332
- payloadType: number;
333
- roundTripTime: number;
334
- roundTripTimeMeasurements: number;
335
- ssrc: number;
336
- timestamp: number;
337
- totalRoundTripTime: number;
338
- transportId: string;
339
- type: string;
340
- };
341
- export declare type ParsedRemoteOutboundStreamStats = {
342
- bytesSent: number;
343
- clockRate: number;
344
- codecId: string;
345
- id: string;
346
- kind: string;
347
- localId: string;
348
- mimeType: string;
349
- packetsSent: number;
350
- payloadType: number;
351
- remoteTimestamp: number;
352
- reportsSent: number;
353
- roundTripTimeMeasurements: number;
354
- ssrc: number;
355
- timestamp: number;
356
- totalRoundTripTime: number;
357
- transportId: string;
358
- type: string;
359
- };
360
- export declare type RemoteParsedStats = {
361
- video: {
362
- inbound: ParsedRemoteInboundStreamStats[];
363
- outbound: ParsedRemoteOutboundStreamStats[];
364
- };
365
- audio: {
366
- inbound: ParsedRemoteInboundStreamStats[];
367
- outbound: ParsedRemoteOutboundStreamStats[];
368
- };
369
- };
370
- export declare type WebRTCStatsParsed = {
371
- audio: {
372
- inbound: ParsedInboundAudioStreamStats[];
373
- outbound: ParsedOutboundAudioStreamStats[];
374
- };
375
- video: {
376
- inbound: ParsedInboundVideoStreamStats[];
377
- outbound: ParsedOutboundVideoStreamStats[];
378
- };
379
- connection: ParsedConnectionStats;
380
- remote: RemoteParsedStats;
381
- };
@@ -1,46 +0,0 @@
1
- import { LogLevel, TrackLabel } from '../../../types/common';
2
- import Logger from '../../Logger';
3
-
4
- export type GetMediaStreamTrackParams = {
5
- label: TrackLabel;
6
- constraints: MediaStreamConstraints;
7
- };
8
-
9
- class MediaStreamTrackManager {
10
- readonly #logger: Logger;
11
-
12
- constructor(logLevel: LogLevel) {
13
- this.#logger = new Logger({
14
- namespace: 'MediaStreamTrackManager',
15
- logLevel,
16
- });
17
- }
18
-
19
- async createMediaStreamTrack({ label, constraints }: GetMediaStreamTrackParams): Promise<MediaStreamTrack> {
20
- if (MediaStreamTrackManager.isDisplayMedia(label)) {
21
- const [track] = await this.createDisplayMediaTracks(constraints);
22
- return track;
23
- }
24
-
25
- const [track] = await this.createUserMediaTracks(constraints);
26
- return track;
27
- }
28
-
29
- private static isDisplayMedia(label: TrackLabel): boolean {
30
- return [TrackLabel.ScreenVideo, TrackLabel.ScreenAudio].includes(label);
31
- }
32
-
33
- async createUserMediaTracks(constraints: MediaStreamConstraints): Promise<MediaStreamTrack[]> {
34
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
35
- this.#logger.debug('createUserMediaTracks() stream created', { streamId: stream.id });
36
- return stream.getTracks();
37
- }
38
-
39
- async createDisplayMediaTracks(constraints: MediaStreamConstraints): Promise<MediaStreamTrack[]> {
40
- const stream = await navigator.mediaDevices.getDisplayMedia(constraints);
41
- this.#logger.debug('getDisplayMediaTracks() stream created', { streamId: stream.id });
42
- return stream.getTracks();
43
- }
44
- }
45
-
46
- export default MediaStreamTrackManager;
@@ -1,136 +0,0 @@
1
- import { WebRTCIssueEmitter } from './WebRTCIssueEmitter';
2
- import {
3
- CompositeStatsParser,
4
- DetectIssuesPayload,
5
- EventType,
6
- IssueDetector,
7
- IssuePayload,
8
- NetworkScoresCalculator,
9
- StatsReportItem,
10
- WebRTCIssueDetectorConstructorParams,
11
- WebRTCStatsParsed,
12
- WIDWindow,
13
- } from './types';
14
- import { Logger } from '../../types/common';
15
- import PeriodicWebRTCStatsReporter from './lib/PeriodicWebRTCStatsReporter';
16
-
17
- class WebRTCIssueDetector {
18
- readonly eventEmitter: WebRTCIssueEmitter;
19
-
20
- #running = false;
21
-
22
- private readonly detectors: IssueDetector[] = [];
23
-
24
- private readonly networkScoresCalculator: NetworkScoresCalculator;
25
-
26
- private readonly statsReporter: PeriodicWebRTCStatsReporter;
27
-
28
- private readonly compositeStatsParser: CompositeStatsParser;
29
-
30
- private readonly logger: Logger;
31
-
32
- constructor(params: WebRTCIssueDetectorConstructorParams) {
33
- this.eventEmitter = params.issueEmitter;
34
-
35
- if (params.onIssues) {
36
- this.eventEmitter.on(EventType.Issue, params.onIssues);
37
- }
38
-
39
- if (params.onNetworkScoresUpdated) {
40
- this.eventEmitter.on(EventType.NetworkScoresUpdated, params.onNetworkScoresUpdated);
41
- }
42
-
43
- this.networkScoresCalculator = params.networkScoresCalculator;
44
- this.detectors = params.detectors;
45
- this.compositeStatsParser = params.compositeStatsParser;
46
- this.statsReporter = params.statsReporter;
47
- this.logger = params.logger;
48
-
49
- (window as unknown as WIDWindow).wid = this;
50
- this.wrapRTCPeerConnection();
51
-
52
- this.statsReporter.on(PeriodicWebRTCStatsReporter.STATS_REPORT_READY_EVENT, (report: StatsReportItem) => {
53
- this.detectIssues({
54
- data: report.stats,
55
- ignoreSSRCList: params.ignoreSSRCList,
56
- });
57
-
58
- this.calculateNetworkScores(report.stats);
59
- });
60
- }
61
-
62
- public watchNewPeerConnections(): void {
63
- if (this.#running) {
64
- throw new Error('WebRTCIssueDetector is already started');
65
- }
66
-
67
- this.#running = true;
68
- this.statsReporter.startReporting();
69
- }
70
-
71
- public stopWatchingNewPeerConnections(): void {
72
- if (!this.#running) {
73
- throw new Error('WebRTCIssueDetector is already stopped');
74
- }
75
-
76
- this.#running = false;
77
- this.statsReporter.stopReporting();
78
- }
79
-
80
- public handleNewPeerConnection(pc: RTCPeerConnection): void {
81
- if (!this.#running) {
82
- this.logger.debug('Skip handling new peer connection. Detector is not running', pc);
83
- return;
84
- }
85
-
86
- this.logger.debug('Handling new peer connection', pc);
87
-
88
- this.compositeStatsParser.addPeerConnection({ pc });
89
- }
90
-
91
- private emitIssues(issues: IssuePayload[]): void {
92
- this.eventEmitter.emit(EventType.Issue, issues);
93
- }
94
-
95
- private detectIssues({ data, ignoreSSRCList }: DetectIssuesPayload): void {
96
- let issues = this.detectors.reduce<IssuePayload[]>((acc, detector) => [...acc, ...detector.detect(data)], []);
97
- if (ignoreSSRCList?.length) {
98
- issues = issues.filter((issue) => {
99
- if (!issue.ssrc) {
100
- return true;
101
- }
102
-
103
- return !ignoreSSRCList.includes(issue.ssrc);
104
- });
105
- }
106
-
107
- if (issues.length > 0) {
108
- this.emitIssues(issues);
109
- }
110
- }
111
-
112
- private calculateNetworkScores(data: WebRTCStatsParsed): void {
113
- const networkScores = this.networkScoresCalculator.calculate(data);
114
- this.eventEmitter.emit(EventType.NetworkScoresUpdated, networkScores);
115
- }
116
-
117
- private wrapRTCPeerConnection(): void {
118
- if (!window.RTCPeerConnection) {
119
- return;
120
- }
121
-
122
- const OriginalRTCPeerConnection = window.RTCPeerConnection;
123
- const onConnectionCreated = (pc: RTCPeerConnection) => this.handleNewPeerConnection(pc);
124
-
125
- function WIDRTCPeerConnection(rtcConfig?: RTCConfiguration) {
126
- const connection = new OriginalRTCPeerConnection(rtcConfig);
127
- onConnectionCreated(connection);
128
- return connection;
129
- }
130
-
131
- WIDRTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype;
132
- (window.RTCPeerConnection as unknown) = WIDRTCPeerConnection;
133
- }
134
- }
135
-
136
- export default WebRTCIssueDetector;
@@ -1,16 +0,0 @@
1
- import { EventEmitter } from 'events';
2
- import {
3
- EventType,
4
- EventPayload,
5
- IssueDetectorResult,
6
- NetworkScores,
7
- } from './types';
8
-
9
- export declare interface WebRTCIssueEmitter {
10
- on(event: EventType.Issue, listener: (payload: IssueDetectorResult) => void): this;
11
- on(event: EventType.NetworkScoresUpdated, listener: (payload: NetworkScores) => void): this;
12
- emit(event: EventType.Issue, payload: EventPayload): boolean;
13
- emit(event: EventType.NetworkScoresUpdated, payload: NetworkScores): boolean;
14
- }
15
-
16
- export class WebRTCIssueEmitter extends EventEmitter {}
@@ -1,57 +0,0 @@
1
- import {
2
- IssueDetector,
3
- IssueDetectorResult,
4
- IssueReason,
5
- IssueType,
6
- WebRTCStatsParsed,
7
- } from '../types';
8
-
9
- class AvailableOutgoingBitrateIssueDetector implements IssueDetector {
10
- #availableOutgoingBitrateTreshhold = 300000; // 300 kbit/s
11
-
12
- detect(data: WebRTCStatsParsed): IssueDetectorResult {
13
- const issues: IssueDetectorResult = [];
14
- const { availableOutgoingBitrate } = data.connection;
15
- if (availableOutgoingBitrate === undefined) {
16
- // availableOutgoingBitrate is not measured yet
17
- return issues;
18
- }
19
-
20
- const audioStreamsTotalTargetBitrate = data.audio.outbound
21
- .reduce((totalBitrate, streamStat) => totalBitrate + streamStat.targetBitrate, 0);
22
-
23
- const videoStreamsTotalBitrate = data.video.outbound
24
- .reduce((totalBitrate, streamStat) => totalBitrate + streamStat.bitrate, 0);
25
-
26
- if (!audioStreamsTotalTargetBitrate && !videoStreamsTotalBitrate) {
27
- // there are no streams sending through this connection
28
- return issues;
29
- }
30
-
31
- if (audioStreamsTotalTargetBitrate > availableOutgoingBitrate) {
32
- issues.push({
33
- type: IssueType.Network,
34
- reason: IssueReason.OutboundNetworkThroughput,
35
- debug: `availableOutgoingBitrate: ${availableOutgoingBitrate}`
36
- + `, audioStreamsTotalTargetBitrate: ${audioStreamsTotalTargetBitrate}`,
37
- });
38
-
39
- return issues;
40
- }
41
-
42
- if (videoStreamsTotalBitrate > 0 && availableOutgoingBitrate < this.#availableOutgoingBitrateTreshhold) {
43
- issues.push({
44
- type: IssueType.Network,
45
- reason: IssueReason.OutboundNetworkThroughput,
46
- debug: `availableOutgoingBitrate: ${availableOutgoingBitrate}`
47
- + `, videoStreamsTotalBitrate: ${videoStreamsTotalBitrate}`,
48
- });
49
-
50
- return issues;
51
- }
52
-
53
- return issues;
54
- }
55
- }
56
-
57
- export default AvailableOutgoingBitrateIssueDetector;
@@ -1,65 +0,0 @@
1
- import {
2
- IssueDetector,
3
- IssueDetectorResult,
4
- IssueReason,
5
- IssueType,
6
- WebRTCStatsParsed,
7
- } from '../types';
8
-
9
- class FramesDroppedIssueDetector implements IssueDetector {
10
- #lastProcessedStats: { [connectionId: string]: WebRTCStatsParsed } = {};
11
-
12
- #framesDroppedTreshold = 0.5;
13
-
14
- detect(data: WebRTCStatsParsed): IssueDetectorResult {
15
- const issues = this.processData(data);
16
- this.#lastProcessedStats[data.connection.id] = data;
17
- return issues;
18
- }
19
-
20
- private processData(data: WebRTCStatsParsed): IssueDetectorResult {
21
- const streamsWithDroppedFrames = data.video.inbound.filter((stats) => stats.framesDropped > 0);
22
- const issues: IssueDetectorResult = [];
23
- const previousInboundRTPVideoStreamsStats = this.#lastProcessedStats[data.connection.id]?.video.inbound;
24
-
25
- if (!previousInboundRTPVideoStreamsStats) {
26
- return issues;
27
- }
28
-
29
- streamsWithDroppedFrames.forEach((streamStats) => {
30
- const previousStreamStats = previousInboundRTPVideoStreamsStats.find((item) => item.ssrc === streamStats.ssrc);
31
- if (!previousStreamStats) {
32
- return;
33
- }
34
-
35
- if (streamStats.framesDropped === previousStreamStats.framesDropped) {
36
- // stream is decoded correctly
37
- return;
38
- }
39
-
40
- const deltaFramesReceived = streamStats.framesReceived - previousStreamStats.framesReceived;
41
- const deltaFramesDecoded = streamStats.framesDecoded - previousStreamStats.framesDecoded;
42
- const deltaFramesDropped = streamStats.framesDropped - previousStreamStats.framesDropped;
43
- if (deltaFramesReceived === 0 && deltaFramesDecoded === 0) {
44
- // looks like stream is stopped, skip checking framesDropped
45
- return;
46
- }
47
-
48
- const framesDropped = deltaFramesDropped / deltaFramesReceived;
49
- if (framesDropped >= this.#framesDroppedTreshold) {
50
- // more than half of the received frames were dropped
51
- issues.push({
52
- type: IssueType.CPU,
53
- reason: IssueReason.DecoderCPUThrottling,
54
- ssrc: streamStats.ssrc,
55
- debug: `framesDropped: ${Math.round(framesDropped * 100)}`
56
- + ` , deltaFramesDropped: ${deltaFramesDropped}, deltaFramesReceived: ${deltaFramesReceived}`,
57
- });
58
- }
59
- });
60
-
61
- return issues;
62
- }
63
- }
64
-
65
- export default FramesDroppedIssueDetector;