@observertc/observer-js 0.41.6 → 0.42.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/ObservedCall.d.ts +10 -3
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +28 -0
- package/lib/ObservedClient.d.ts +4 -0
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +81 -32
- package/lib/ObservedInboundAudioTrack.d.ts +94 -0
- package/lib/ObservedInboundAudioTrack.d.ts.map +1 -0
- package/lib/ObservedInboundAudioTrack.js +215 -0
- package/lib/ObservedInboundVideoTrack.d.ts +98 -0
- package/lib/ObservedInboundVideoTrack.d.ts.map +1 -0
- package/lib/{ObservedInboundTrack.js → ObservedInboundVideoTrack.js} +53 -44
- package/lib/ObservedOutboundAudioTrack.d.ts +85 -0
- package/lib/ObservedOutboundAudioTrack.d.ts.map +1 -0
- package/lib/{ObservedOutboundTrack.js → ObservedOutboundAudioTrack.js} +35 -58
- package/lib/ObservedOutboundVideoTrack.d.ts +88 -0
- package/lib/ObservedOutboundVideoTrack.d.ts.map +1 -0
- package/lib/ObservedOutboundVideoTrack.js +204 -0
- package/lib/ObservedPeerConnection.d.ts +26 -16
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +157 -86
- package/lib/RemoteTrackAssigner.d.ts +14 -0
- package/lib/RemoteTrackAssigner.d.ts.map +1 -0
- package/lib/RemoteTrackAssigner.js +52 -0
- package/lib/common/CalculatedScore.d.ts +79 -0
- package/lib/common/CalculatedScore.d.ts.map +1 -0
- package/lib/common/CalculatedScore.js +155 -0
- package/lib/common/CallEventType.d.ts +13 -1
- package/lib/common/CallEventType.d.ts.map +1 -1
- package/lib/common/CallEventType.js +12 -0
- package/lib/common/QualityScoreUtils.d.ts +1 -0
- package/lib/common/QualityScoreUtils.d.ts.map +1 -0
- package/lib/common/QualityScoreUtils.js +1 -0
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +14 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/monitors/ClientQualityMonitor.d.ts +1 -0
- package/lib/monitors/ClientQualityMonitor.d.ts.map +1 -0
- package/lib/monitors/ClientQualityMonitor.js +1 -0
- package/package.json +1 -1
- package/src/ObservedCall.ts +40 -4
- package/src/ObservedClient.ts +77 -17
- package/src/ObservedInboundAudioTrack.ts +336 -0
- package/src/{ObservedInboundTrack.ts → ObservedInboundVideoTrack.ts} +85 -66
- package/src/{ObservedOutboundTrack.ts → ObservedOutboundAudioTrack.ts} +59 -74
- package/src/ObservedOutboundVideoTrack.ts +326 -0
- package/src/ObservedPeerConnection.ts +205 -131
- package/src/RemoteTrackAssigner.ts +68 -0
- package/src/common/CalculatedScore.ts +180 -0
- package/src/common/CallEventType.ts +14 -1
- package/src/common/QualityScoreUtils.ts +0 -0
- package/src/common/utils.ts +17 -1
- package/src/index.ts +4 -2
- package/src/monitors/CallSummaryMonitor.ts +3 -3
- package/src/monitors/ClientQualityMonitor.ts +0 -0
- package/lib/ObservedInboundTrack.d.ts +0 -96
- package/lib/ObservedInboundTrack.d.ts.map +0 -1
- package/lib/ObservedOutboundTrack.d.ts +0 -84
- package/lib/ObservedOutboundTrack.d.ts.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=QualityScoreUtils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QualityScoreUtils.d.ts","sourceRoot":"","sources":["../../src/common/QualityScoreUtils.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
package/lib/common/utils.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export type Writable<T> = T extends object ? {
|
|
|
5
5
|
export declare function iteratorConverter<T>(generator: Generator<T, void, undefined>): IterableIterator<T>;
|
|
6
6
|
export declare function asyncIteratorConverter<T>(generator: AsyncGenerator<T, void, undefined>): AsyncIterableIterator<T>;
|
|
7
7
|
export declare function isValidUuid(str: string): boolean;
|
|
8
|
+
export declare function getMedian(arr: number[]): number;
|
|
8
9
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/common/utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE/E,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG;IAAE,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,CAAC,CAAC;AAE9F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CASlG;AAED,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CASjH;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIhD"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/common/utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE/E,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAAG;IAAE,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,CAAC,CAAC;AAE9F,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CASlG;AAED,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CASjH;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIhD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,CAc/C"}
|
package/lib/common/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isValidUuid = exports.asyncIteratorConverter = exports.iteratorConverter = void 0;
|
|
3
|
+
exports.getMedian = exports.isValidUuid = exports.asyncIteratorConverter = exports.iteratorConverter = void 0;
|
|
4
4
|
function iteratorConverter(generator) {
|
|
5
5
|
return {
|
|
6
6
|
[Symbol.iterator]() {
|
|
@@ -28,3 +28,16 @@ function isValidUuid(str) {
|
|
|
28
28
|
return regexp.test(str);
|
|
29
29
|
}
|
|
30
30
|
exports.isValidUuid = isValidUuid;
|
|
31
|
+
function getMedian(arr) {
|
|
32
|
+
// Sort the array in ascending order
|
|
33
|
+
const sortedArr = arr.slice().sort((a, b) => a - b);
|
|
34
|
+
// Calculate the middle index
|
|
35
|
+
const mid = Math.floor(sortedArr.length / 2);
|
|
36
|
+
// If the array length is odd, return the middle element
|
|
37
|
+
if (sortedArr.length % 2 !== 0) {
|
|
38
|
+
return sortedArr[mid];
|
|
39
|
+
}
|
|
40
|
+
// If the array length is even, return the average of the two middle elements
|
|
41
|
+
return (sortedArr[mid - 1] + sortedArr[mid]) / 2;
|
|
42
|
+
}
|
|
43
|
+
exports.getMedian = getMedian;
|
package/lib/index.d.ts
CHANGED
|
@@ -9,8 +9,10 @@ export type { ClientIssueMonitorConfig, ClientIssueMonitorEmittedIssueEvent, Cli
|
|
|
9
9
|
export type { ObservedCall, ObservedCallModel } from './ObservedCall';
|
|
10
10
|
export type { ObservedClient, ObservedClientModel } from './ObservedClient';
|
|
11
11
|
export type { ObservedPeerConnection, ObservedPeerConnectionModel, ObservedPeerConnectionEvents } from './ObservedPeerConnection';
|
|
12
|
-
export type {
|
|
13
|
-
export type {
|
|
12
|
+
export type { ObservedInboundAudioTrack, ObservedInboundAudioTrackModel, ObservedInboundAudioTrackEvents } from './ObservedInboundAudioTrack';
|
|
13
|
+
export type { ObservedOutboundAudioTrack, ObservedOutboundAudioTrackModel, ObservedOutboundAudioTrackEvents } from './ObservedOutboundAudioTrack';
|
|
14
|
+
export type { ObservedInboundVideoTrack, ObservedInboundVideoTrackModel, ObservedInboundVideoTrackEvents } from './ObservedInboundVideoTrack';
|
|
15
|
+
export type { ObservedOutboundVideoTrack, ObservedOutboundVideoTrackModel, ObservedOutboundVideoTrackEvents } from './ObservedOutboundVideoTrack';
|
|
14
16
|
export type { CallSummary, ClientSummary, ClientIssue } from './monitors/CallSummary';
|
|
15
17
|
export type { ObserverSinkContext } from './common/types';
|
|
16
18
|
export type { SfuServerMonitorMetricsRecord } from './monitors/SfuServerMonitor';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAE9D,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAExD,YAAY,EACX,OAAO,EACP,YAAY,EACZ,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,WAAW,GACX,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACX,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACX,wBAAwB,EACxB,mCAAmC,EACnC,kBAAkB,EAClB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAClI,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAE9D,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAExD,YAAY,EACX,OAAO,EACP,YAAY,EACZ,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,WAAW,GACX,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACX,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACX,wBAAwB,EACxB,mCAAmC,EACnC,kBAAkB,EAClB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAClI,YAAY,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAC9I,YAAY,EAAE,0BAA0B,EAAE,+BAA+B,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAClJ,YAAY,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAC9I,YAAY,EAAE,0BAA0B,EAAE,+BAA+B,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAClJ,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACtF,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AACjF,YAAY,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAClH,OAAO,EACN,aAAa,EACb,mBAAmB,EACnB,yBAAyB,EACzB,mCAAmC,EACnC,kCAAkC,EAClC,oCAAoC,GACpC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEpG,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtD,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,YAE9D;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA8B,MAAM,iBAAiB,CAAC;AAC/E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAG3D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=ClientQualityMonitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientQualityMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/ClientQualityMonitor.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
package/package.json
CHANGED
package/src/ObservedCall.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
import { ObservedClient, ObservedClientEvents, ObservedClientModel } from './ObservedClient';
|
|
3
|
-
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
4
3
|
import { Observer } from './Observer';
|
|
5
4
|
import { createClientJoinedEventReport } from './common/callEventReports';
|
|
6
|
-
import { PartialBy } from './common/utils';
|
|
5
|
+
import { getMedian, PartialBy } from './common/utils';
|
|
7
6
|
import { CallEventReport } from '@observertc/report-schemas-js';
|
|
8
7
|
import { createProcessor } from './common/Middleware';
|
|
9
8
|
import { ClientSample } from '@observertc/sample-schemas-js';
|
|
10
9
|
import { ClientIssue } from './monitors/CallSummary';
|
|
10
|
+
import { ObservedOutboundAudioTrack } from './ObservedOutboundAudioTrack';
|
|
11
|
+
import { ObservedOutboundVideoTrack } from './ObservedOutboundVideoTrack';
|
|
12
|
+
import { CalculatedScore } from './common/CalculatedScore';
|
|
11
13
|
|
|
12
14
|
type ClientIssueDetectionConfig = Pick<ClientIssue, 'severity'>;
|
|
13
15
|
|
|
@@ -38,8 +40,13 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
38
40
|
|
|
39
41
|
private readonly _clients = new Map<string, ObservedClient>();
|
|
40
42
|
|
|
41
|
-
public
|
|
42
|
-
|
|
43
|
+
public _scoreData?: {
|
|
44
|
+
score: CalculatedScore,
|
|
45
|
+
calculated: number,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
public readonly sfuStreamIdToOutboundAudioTrack = new Map<string | number, ObservedOutboundAudioTrack>();
|
|
49
|
+
public readonly sfuStreamIdToOutboundVideoTrack = new Map<string | number, ObservedOutboundVideoTrack>();
|
|
43
50
|
private _closed = false;
|
|
44
51
|
private _updated = Date.now();
|
|
45
52
|
private _ended?: number;
|
|
@@ -84,6 +91,35 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
84
91
|
return this._clients;
|
|
85
92
|
}
|
|
86
93
|
|
|
94
|
+
public get score(): CalculatedScore | undefined {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
|
|
97
|
+
if (now - 15000 < (this._scoreData?.calculated ?? 0)) {
|
|
98
|
+
return this._scoreData?.score;
|
|
99
|
+
} else if (this.clients.size < 1) {
|
|
100
|
+
return {
|
|
101
|
+
remarks: [ {
|
|
102
|
+
severity: 'none',
|
|
103
|
+
text: 'No clients',
|
|
104
|
+
} ],
|
|
105
|
+
score: 5.0,
|
|
106
|
+
timestamp: now,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const scores = [ ...this.clients.values() ].map((client) => client.score?.score ?? 5.0);
|
|
110
|
+
|
|
111
|
+
this._scoreData = {
|
|
112
|
+
score: {
|
|
113
|
+
remarks: [],
|
|
114
|
+
score: getMedian(scores),
|
|
115
|
+
timestamp: now,
|
|
116
|
+
},
|
|
117
|
+
calculated: now,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return this._scoreData.score;
|
|
121
|
+
}
|
|
122
|
+
|
|
87
123
|
public get closed() {
|
|
88
124
|
return this._closed;
|
|
89
125
|
}
|
package/src/ObservedClient.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { CallEventType } from './common/CallEventType';
|
|
|
11
11
|
import { ObservedSfu } from './ObservedSfu';
|
|
12
12
|
import { ClientIssue } from './monitors/CallSummary';
|
|
13
13
|
import { CallEventReport } from '@observertc/report-schemas-js';
|
|
14
|
+
import { CalculatedScore } from './common/CalculatedScore';
|
|
14
15
|
|
|
15
16
|
const logger = createLogger('ObservedClient');
|
|
16
17
|
|
|
@@ -59,6 +60,7 @@ export type ObservedClientEvents = {
|
|
|
59
60
|
rejoined: [{
|
|
60
61
|
lastJoined: number,
|
|
61
62
|
}],
|
|
63
|
+
score: [CalculatedScore],
|
|
62
64
|
};
|
|
63
65
|
|
|
64
66
|
export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
|
|
@@ -84,6 +86,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
84
86
|
private _timeZoneOffsetInHours?: number;
|
|
85
87
|
private _left?: number;
|
|
86
88
|
|
|
89
|
+
public score?: CalculatedScore;
|
|
87
90
|
public usingTURN = false;
|
|
88
91
|
public availableOutgoingBitrate = 0;
|
|
89
92
|
public availableIncomingBitrate = 0;
|
|
@@ -238,7 +241,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
238
241
|
if (!this._left) {
|
|
239
242
|
this._addClientLeftReport();
|
|
240
243
|
}
|
|
241
|
-
|
|
242
244
|
Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
243
245
|
|
|
244
246
|
this.emit('close');
|
|
@@ -302,8 +304,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
302
304
|
logger.warn(`Error adding client issue: ${(err as Error)?.message}`);
|
|
303
305
|
}
|
|
304
306
|
|
|
305
|
-
this.
|
|
306
|
-
this.emit('issue', issue);
|
|
307
|
+
this._addAndEmitIssue(issue);
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
public accept(sample: ClientSample): void {
|
|
@@ -515,9 +516,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
515
516
|
trackId: callEvent.mediaTrackId,
|
|
516
517
|
attachments: callEvent.attachments ? JSON.parse(callEvent.attachments) : undefined,
|
|
517
518
|
};
|
|
518
|
-
|
|
519
|
-
this.
|
|
520
|
-
this.emit('issue', issue);
|
|
519
|
+
|
|
520
|
+
this._addAndEmitIssue(issue);
|
|
521
521
|
} catch (err) {
|
|
522
522
|
logger.warn(`Error parsing client issue: ${(err as Error)?.message}`);
|
|
523
523
|
}
|
|
@@ -619,7 +619,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
619
619
|
type: CallMetaType.MEDIA_DEVICE,
|
|
620
620
|
payload: mediaDevice,
|
|
621
621
|
}, this.userId);
|
|
622
|
-
|
|
622
|
+
|
|
623
623
|
this.reports.addCallMetaReport(callMetaReport);
|
|
624
624
|
mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
|
|
625
625
|
}
|
|
@@ -634,7 +634,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
634
634
|
type: CallMetaType.MEDIA_SOURCE,
|
|
635
635
|
payload: mediaSource,
|
|
636
636
|
}, this.userId);
|
|
637
|
-
|
|
637
|
+
|
|
638
638
|
this.reports.addCallMetaReport(callMetaReport);
|
|
639
639
|
}
|
|
640
640
|
|
|
@@ -670,10 +670,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
670
670
|
|
|
671
671
|
inboundAudioTrack.update(track, sample.timestamp);
|
|
672
672
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
remoteOutboundTrack
|
|
673
|
+
if (!inboundAudioTrack.remoteOutboundTrack) {
|
|
674
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(inboundAudioTrack.sfuStreamId ?? '');
|
|
675
|
+
|
|
676
|
+
if (remoteOutboundTrack) {
|
|
677
|
+
inboundAudioTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
678
|
+
|
|
679
|
+
inboundAudioTrack.once('close', () => {
|
|
680
|
+
remoteOutboundTrack?.remoteInboundTracks.delete(inboundAudioTrack.trackId ?? '');
|
|
681
|
+
});
|
|
682
|
+
remoteOutboundTrack.remoteInboundTracks.set(inboundAudioTrack.trackId ?? '', inboundAudioTrack);
|
|
683
|
+
}
|
|
677
684
|
}
|
|
678
685
|
} catch (err) {
|
|
679
686
|
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
@@ -705,11 +712,18 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
705
712
|
});
|
|
706
713
|
|
|
707
714
|
inboundVideoTrack.update(track, sample.timestamp);
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
remoteOutboundTrack
|
|
715
|
+
|
|
716
|
+
if (!inboundVideoTrack.remoteOutboundTrack) {
|
|
717
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
|
|
718
|
+
|
|
719
|
+
if (remoteOutboundTrack) {
|
|
720
|
+
inboundVideoTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
721
|
+
|
|
722
|
+
inboundVideoTrack.once('close', () => {
|
|
723
|
+
remoteOutboundTrack?.remoteInboundTracks.delete(inboundVideoTrack.trackId ?? '');
|
|
724
|
+
});
|
|
725
|
+
remoteOutboundTrack.remoteInboundTracks.set(inboundVideoTrack.trackId ?? '', inboundVideoTrack);
|
|
726
|
+
}
|
|
713
727
|
}
|
|
714
728
|
} catch (err) {
|
|
715
729
|
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
@@ -734,6 +748,11 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
734
748
|
});
|
|
735
749
|
|
|
736
750
|
outboundAudioTrack.update(track, sample.timestamp);
|
|
751
|
+
|
|
752
|
+
if (outboundAudioTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundAudioTrack.has(outboundAudioTrack.sfuStreamId)) {
|
|
753
|
+
this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
|
|
754
|
+
}
|
|
755
|
+
|
|
737
756
|
} catch (err) {
|
|
738
757
|
logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
|
|
739
758
|
}
|
|
@@ -759,6 +778,10 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
759
778
|
|
|
760
779
|
outboundVideoTrack.update(track, sample.timestamp);
|
|
761
780
|
|
|
781
|
+
if (outboundVideoTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundVideoTrack.has(outboundVideoTrack.sfuStreamId)) {
|
|
782
|
+
this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
|
|
783
|
+
}
|
|
784
|
+
|
|
762
785
|
} catch (err) {
|
|
763
786
|
logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
|
|
764
787
|
}
|
|
@@ -897,6 +920,9 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
897
920
|
let sumRttInMs = 0;
|
|
898
921
|
let anyPeerConnectionUsingTurn = false;
|
|
899
922
|
|
|
923
|
+
let minPcScore = Number.MAX_SAFE_INTEGER;
|
|
924
|
+
let maxPcScore = Number.MIN_SAFE_INTEGER;
|
|
925
|
+
|
|
900
926
|
for (const peerConnection of this._peerConnections.values()) {
|
|
901
927
|
if (peerConnection.closed) continue;
|
|
902
928
|
peerConnection.updateMetrics();
|
|
@@ -916,8 +942,21 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
916
942
|
sumRttInMs += peerConnection.avgRttInMs ?? 0;
|
|
917
943
|
|
|
918
944
|
anyPeerConnectionUsingTurn ||= peerConnection.usingTURN;
|
|
945
|
+
|
|
946
|
+
minPcScore = Math.min(minPcScore, peerConnection.score?.score ?? Number.MAX_SAFE_INTEGER);
|
|
947
|
+
maxPcScore = Math.max(maxPcScore, peerConnection.score?.score ?? Number.MIN_SAFE_INTEGER);
|
|
919
948
|
}
|
|
920
949
|
|
|
950
|
+
this.score = {
|
|
951
|
+
score: minPcScore,
|
|
952
|
+
remarks: [ {
|
|
953
|
+
severity: 'none',
|
|
954
|
+
text: `Min and max score of all peer connections: ${minPcScore}, ${maxPcScore}`,
|
|
955
|
+
} ],
|
|
956
|
+
timestamp: sample.timestamp,
|
|
957
|
+
};
|
|
958
|
+
this.emit('score', this.score);
|
|
959
|
+
|
|
921
960
|
this.usingTURN = anyPeerConnectionUsingTurn === true;
|
|
922
961
|
|
|
923
962
|
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
@@ -951,6 +990,27 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
951
990
|
});
|
|
952
991
|
}
|
|
953
992
|
|
|
993
|
+
private _addAndEmitIssue(issue: ClientIssue) {
|
|
994
|
+
this.issues.push(issue);
|
|
995
|
+
|
|
996
|
+
if (issue.peerConnectionId) {
|
|
997
|
+
const peerConnection = this._peerConnections.get(issue.peerConnectionId);
|
|
998
|
+
|
|
999
|
+
if (peerConnection) {
|
|
1000
|
+
|
|
1001
|
+
if (issue.trackId) {
|
|
1002
|
+
const track = peerConnection.inboundAudioTracks.get(issue.trackId) ?? peerConnection.inboundVideoTracks.get(issue.trackId);
|
|
1003
|
+
|
|
1004
|
+
if (track) track.ωpendingIssuesForScores.push(issue);
|
|
1005
|
+
} else {
|
|
1006
|
+
peerConnection.ωpendingIssuesForScores.push(issue);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
this.emit('issue', issue);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
954
1014
|
private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
|
|
955
1015
|
const result = new ObservedPeerConnection({
|
|
956
1016
|
peerConnectionId,
|