@observertc/observer-js 0.41.7 → 0.42.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/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 +5 -0
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +83 -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/Observer.d.ts +1 -0
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +2 -2
- 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/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/package.json +1 -1
- package/src/ObservedCall.ts +40 -4
- package/src/ObservedClient.ts +79 -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/Observer.ts +3 -2
- package/src/RemoteTrackAssigner.ts +68 -0
- package/src/common/CalculatedScore.ts +180 -0
- 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/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
|
+
{"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"}
|
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;
|
|
@@ -114,6 +117,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
114
117
|
public outboundVideoBitrate?: number;
|
|
115
118
|
public inboundAudioBitrate?: number;
|
|
116
119
|
public inboundVideoBitrate?: number;
|
|
120
|
+
public mediaConstraints: string[] = [];
|
|
117
121
|
|
|
118
122
|
public readonly mediaDevices: string[] = [];
|
|
119
123
|
public readonly codecs: string[] = [];
|
|
@@ -238,7 +242,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
238
242
|
if (!this._left) {
|
|
239
243
|
this._addClientLeftReport();
|
|
240
244
|
}
|
|
241
|
-
|
|
242
245
|
Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
243
246
|
|
|
244
247
|
this.emit('close');
|
|
@@ -302,8 +305,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
302
305
|
logger.warn(`Error adding client issue: ${(err as Error)?.message}`);
|
|
303
306
|
}
|
|
304
307
|
|
|
305
|
-
this.
|
|
306
|
-
this.emit('issue', issue);
|
|
308
|
+
this._addAndEmitIssue(issue);
|
|
307
309
|
}
|
|
308
310
|
|
|
309
311
|
public accept(sample: ClientSample): void {
|
|
@@ -452,6 +454,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
452
454
|
);
|
|
453
455
|
|
|
454
456
|
this.reports.addCallMetaReport(callMetaReport);
|
|
457
|
+
this.mediaConstraints.push(mediaConstraint);
|
|
455
458
|
}
|
|
456
459
|
|
|
457
460
|
for (const localSDP of sample.localSDPs ?? []) {
|
|
@@ -515,9 +518,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
515
518
|
trackId: callEvent.mediaTrackId,
|
|
516
519
|
attachments: callEvent.attachments ? JSON.parse(callEvent.attachments) : undefined,
|
|
517
520
|
};
|
|
518
|
-
|
|
519
|
-
this.
|
|
520
|
-
this.emit('issue', issue);
|
|
521
|
+
|
|
522
|
+
this._addAndEmitIssue(issue);
|
|
521
523
|
} catch (err) {
|
|
522
524
|
logger.warn(`Error parsing client issue: ${(err as Error)?.message}`);
|
|
523
525
|
}
|
|
@@ -619,7 +621,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
619
621
|
type: CallMetaType.MEDIA_DEVICE,
|
|
620
622
|
payload: mediaDevice,
|
|
621
623
|
}, this.userId);
|
|
622
|
-
|
|
624
|
+
|
|
623
625
|
this.reports.addCallMetaReport(callMetaReport);
|
|
624
626
|
mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
|
|
625
627
|
}
|
|
@@ -634,7 +636,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
634
636
|
type: CallMetaType.MEDIA_SOURCE,
|
|
635
637
|
payload: mediaSource,
|
|
636
638
|
}, this.userId);
|
|
637
|
-
|
|
639
|
+
|
|
638
640
|
this.reports.addCallMetaReport(callMetaReport);
|
|
639
641
|
}
|
|
640
642
|
|
|
@@ -670,10 +672,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
670
672
|
|
|
671
673
|
inboundAudioTrack.update(track, sample.timestamp);
|
|
672
674
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
remoteOutboundTrack
|
|
675
|
+
if (!inboundAudioTrack.remoteOutboundTrack) {
|
|
676
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(inboundAudioTrack.sfuStreamId ?? '');
|
|
677
|
+
|
|
678
|
+
if (remoteOutboundTrack) {
|
|
679
|
+
inboundAudioTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
680
|
+
|
|
681
|
+
inboundAudioTrack.once('close', () => {
|
|
682
|
+
remoteOutboundTrack?.remoteInboundTracks.delete(inboundAudioTrack.trackId ?? '');
|
|
683
|
+
});
|
|
684
|
+
remoteOutboundTrack.remoteInboundTracks.set(inboundAudioTrack.trackId ?? '', inboundAudioTrack);
|
|
685
|
+
}
|
|
677
686
|
}
|
|
678
687
|
} catch (err) {
|
|
679
688
|
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
@@ -705,11 +714,18 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
705
714
|
});
|
|
706
715
|
|
|
707
716
|
inboundVideoTrack.update(track, sample.timestamp);
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
remoteOutboundTrack
|
|
717
|
+
|
|
718
|
+
if (!inboundVideoTrack.remoteOutboundTrack) {
|
|
719
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
|
|
720
|
+
|
|
721
|
+
if (remoteOutboundTrack) {
|
|
722
|
+
inboundVideoTrack.remoteOutboundTrack = remoteOutboundTrack;
|
|
723
|
+
|
|
724
|
+
inboundVideoTrack.once('close', () => {
|
|
725
|
+
remoteOutboundTrack?.remoteInboundTracks.delete(inboundVideoTrack.trackId ?? '');
|
|
726
|
+
});
|
|
727
|
+
remoteOutboundTrack.remoteInboundTracks.set(inboundVideoTrack.trackId ?? '', inboundVideoTrack);
|
|
728
|
+
}
|
|
713
729
|
}
|
|
714
730
|
} catch (err) {
|
|
715
731
|
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
@@ -734,6 +750,11 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
734
750
|
});
|
|
735
751
|
|
|
736
752
|
outboundAudioTrack.update(track, sample.timestamp);
|
|
753
|
+
|
|
754
|
+
if (outboundAudioTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundAudioTrack.has(outboundAudioTrack.sfuStreamId)) {
|
|
755
|
+
this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
|
|
756
|
+
}
|
|
757
|
+
|
|
737
758
|
} catch (err) {
|
|
738
759
|
logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
|
|
739
760
|
}
|
|
@@ -759,6 +780,10 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
759
780
|
|
|
760
781
|
outboundVideoTrack.update(track, sample.timestamp);
|
|
761
782
|
|
|
783
|
+
if (outboundVideoTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundVideoTrack.has(outboundVideoTrack.sfuStreamId)) {
|
|
784
|
+
this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
|
|
785
|
+
}
|
|
786
|
+
|
|
762
787
|
} catch (err) {
|
|
763
788
|
logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
|
|
764
789
|
}
|
|
@@ -897,6 +922,9 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
897
922
|
let sumRttInMs = 0;
|
|
898
923
|
let anyPeerConnectionUsingTurn = false;
|
|
899
924
|
|
|
925
|
+
let minPcScore = Number.MAX_SAFE_INTEGER;
|
|
926
|
+
let maxPcScore = Number.MIN_SAFE_INTEGER;
|
|
927
|
+
|
|
900
928
|
for (const peerConnection of this._peerConnections.values()) {
|
|
901
929
|
if (peerConnection.closed) continue;
|
|
902
930
|
peerConnection.updateMetrics();
|
|
@@ -916,8 +944,21 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
916
944
|
sumRttInMs += peerConnection.avgRttInMs ?? 0;
|
|
917
945
|
|
|
918
946
|
anyPeerConnectionUsingTurn ||= peerConnection.usingTURN;
|
|
947
|
+
|
|
948
|
+
minPcScore = Math.min(minPcScore, peerConnection.score?.score ?? Number.MAX_SAFE_INTEGER);
|
|
949
|
+
maxPcScore = Math.max(maxPcScore, peerConnection.score?.score ?? Number.MIN_SAFE_INTEGER);
|
|
919
950
|
}
|
|
920
951
|
|
|
952
|
+
this.score = {
|
|
953
|
+
score: minPcScore,
|
|
954
|
+
remarks: [ {
|
|
955
|
+
severity: 'none',
|
|
956
|
+
text: `Min and max score of all peer connections: ${minPcScore}, ${maxPcScore}`,
|
|
957
|
+
} ],
|
|
958
|
+
timestamp: sample.timestamp,
|
|
959
|
+
};
|
|
960
|
+
this.emit('score', this.score);
|
|
961
|
+
|
|
921
962
|
this.usingTURN = anyPeerConnectionUsingTurn === true;
|
|
922
963
|
|
|
923
964
|
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
@@ -951,6 +992,27 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
951
992
|
});
|
|
952
993
|
}
|
|
953
994
|
|
|
995
|
+
private _addAndEmitIssue(issue: ClientIssue) {
|
|
996
|
+
this.issues.push(issue);
|
|
997
|
+
|
|
998
|
+
if (issue.peerConnectionId) {
|
|
999
|
+
const peerConnection = this._peerConnections.get(issue.peerConnectionId);
|
|
1000
|
+
|
|
1001
|
+
if (peerConnection) {
|
|
1002
|
+
|
|
1003
|
+
if (issue.trackId) {
|
|
1004
|
+
const track = peerConnection.inboundAudioTracks.get(issue.trackId) ?? peerConnection.inboundVideoTracks.get(issue.trackId);
|
|
1005
|
+
|
|
1006
|
+
if (track) track.ωpendingIssuesForScores.push(issue);
|
|
1007
|
+
} else {
|
|
1008
|
+
peerConnection.ωpendingIssuesForScores.push(issue);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
this.emit('issue', issue);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
954
1016
|
private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
|
|
955
1017
|
const result = new ObservedPeerConnection({
|
|
956
1018
|
peerConnectionId,
|