@observertc/observer-js 0.40.29 → 0.40.30
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 +8 -0
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +20 -2
- package/lib/ObservedClient.d.ts +21 -2
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +21 -4
- package/lib/common/Middleware.d.ts +8 -0
- package/lib/common/Middleware.d.ts.map +1 -0
- package/lib/common/Middleware.js +41 -0
- package/lib/monitors/ClientIssueMonitor.d.ts +1 -4
- package/lib/monitors/ClientIssueMonitor.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ObservedCall.ts +48 -4
- package/src/ObservedClient.ts +35 -4
- package/src/common/Middleware.ts +56 -0
- package/src/monitors/ClientIssueMonitor.ts +1 -2
package/lib/ObservedCall.d.ts
CHANGED
|
@@ -5,6 +5,9 @@ import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
|
5
5
|
import { Observer } from './Observer';
|
|
6
6
|
import { PartialBy } from './common/utils';
|
|
7
7
|
import { CallEventReport } from '@observertc/report-schemas-js';
|
|
8
|
+
import { ClientSample } from '@observertc/sample-schemas-js';
|
|
9
|
+
import { ClientIssue } from './monitors/CallSummary';
|
|
10
|
+
type ClientIssueDetectionConfig = Pick<ClientIssue, 'severity'>;
|
|
8
11
|
export type ObservedCallModel = {
|
|
9
12
|
serviceId: string;
|
|
10
13
|
roomId: string;
|
|
@@ -26,6 +29,7 @@ export declare class ObservedCall<AppData extends Record<string, unknown> = Reco
|
|
|
26
29
|
readonly observer: Observer;
|
|
27
30
|
readonly appData: AppData;
|
|
28
31
|
readonly created: number;
|
|
32
|
+
readonly processor: import("./common/Middleware").Processor<ClientSample>;
|
|
29
33
|
private readonly _clients;
|
|
30
34
|
readonly sfuStreamIdToOutboundAudioTrack: Map<string | number, ObservedOutboundTrack<"audio">>;
|
|
31
35
|
readonly sfuStreamIdToOutboundVideoTrack: Map<string | number, ObservedOutboundTrack<"video">>;
|
|
@@ -47,6 +51,10 @@ export declare class ObservedCall<AppData extends Record<string, unknown> = Reco
|
|
|
47
51
|
appData: ClientAppData;
|
|
48
52
|
generateClientJoinedReport?: boolean;
|
|
49
53
|
joined?: number;
|
|
54
|
+
detectIssues?: {
|
|
55
|
+
rejoin: ClientIssue['severity'] | ClientIssueDetectionConfig;
|
|
56
|
+
};
|
|
50
57
|
}): ObservedClient<ClientAppData>;
|
|
51
58
|
}
|
|
59
|
+
export {};
|
|
52
60
|
//# sourceMappingURL=ObservedCall.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedCall.d.ts","sourceRoot":"","sources":["../src/ObservedCall.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"ObservedCall.d.ts","sourceRoot":"","sources":["../src/ObservedCall.ts"],"names":[],"mappings":"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"}
|
package/lib/ObservedCall.js
CHANGED
|
@@ -15,6 +15,7 @@ exports.ObservedCall = void 0;
|
|
|
15
15
|
const events_1 = require("events");
|
|
16
16
|
const ObservedClient_1 = require("./ObservedClient");
|
|
17
17
|
const callEventReports_1 = require("./common/callEventReports");
|
|
18
|
+
const Middleware_1 = require("./common/Middleware");
|
|
18
19
|
class ObservedCall extends events_1.EventEmitter {
|
|
19
20
|
constructor(_model, observer, appData) {
|
|
20
21
|
super();
|
|
@@ -22,6 +23,7 @@ class ObservedCall extends events_1.EventEmitter {
|
|
|
22
23
|
this.observer = observer;
|
|
23
24
|
this.appData = appData;
|
|
24
25
|
this.created = Date.now();
|
|
26
|
+
this.processor = (0, Middleware_1.createProcessor)();
|
|
25
27
|
this._clients = new Map();
|
|
26
28
|
this.sfuStreamIdToOutboundAudioTrack = new Map();
|
|
27
29
|
this.sfuStreamIdToOutboundVideoTrack = new Map();
|
|
@@ -71,11 +73,14 @@ class ObservedCall extends events_1.EventEmitter {
|
|
|
71
73
|
createClient(config) {
|
|
72
74
|
if (this._closed)
|
|
73
75
|
throw new Error(`Call ${this.callId} is closed`);
|
|
74
|
-
const { appData, generateClientJoinedReport, joined = Date.now()
|
|
76
|
+
const { appData, generateClientJoinedReport, joined = Date.now(), detectIssues = {
|
|
77
|
+
rejoin: 'minor'
|
|
78
|
+
} } = config, model = __rest(config, ["appData", "generateClientJoinedReport", "joined", "detectIssues"]);
|
|
75
79
|
const result = new ObservedClient_1.ObservedClient(model, this, appData);
|
|
76
|
-
const onUpdate = () => {
|
|
80
|
+
const onUpdate = ({ sample }) => {
|
|
77
81
|
this._updated = Date.now();
|
|
78
82
|
this.emit('update');
|
|
83
|
+
this.processor.process(sample);
|
|
79
84
|
};
|
|
80
85
|
result.once('close', () => {
|
|
81
86
|
result.off('update', onUpdate);
|
|
@@ -86,6 +91,19 @@ class ObservedCall extends events_1.EventEmitter {
|
|
|
86
91
|
if (generateClientJoinedReport) {
|
|
87
92
|
this.reports.addCallEventReport((0, callEventReports_1.createClientJoinedEventReport)(this.serviceId, result.mediaUnitId, this.roomId, this.callId, result.clientId, joined, result.userId, result.marker));
|
|
88
93
|
}
|
|
94
|
+
if (detectIssues === null || detectIssues === void 0 ? void 0 : detectIssues.rejoin) {
|
|
95
|
+
const issueBaseConfig = typeof detectIssues.rejoin === 'object' ? detectIssues.rejoin : {
|
|
96
|
+
severity: detectIssues.rejoin
|
|
97
|
+
};
|
|
98
|
+
const rejoinedClientIssueListener = (event) => {
|
|
99
|
+
event.lastJoined;
|
|
100
|
+
result.addIssue(Object.assign({ timestamp: Date.now() }, issueBaseConfig));
|
|
101
|
+
};
|
|
102
|
+
result.once('close', () => {
|
|
103
|
+
result.off('rejoined', rejoinedClientIssueListener);
|
|
104
|
+
});
|
|
105
|
+
result.on('rejoined', rejoinedClientIssueListener);
|
|
106
|
+
}
|
|
89
107
|
this.emit('newclient', result);
|
|
90
108
|
return result;
|
|
91
109
|
}
|
package/lib/ObservedClient.d.ts
CHANGED
|
@@ -16,10 +16,15 @@ export type ObservedClientModel = {
|
|
|
16
16
|
engine?: Engine;
|
|
17
17
|
platform?: Platform;
|
|
18
18
|
browser?: Browser;
|
|
19
|
+
coordinates?: {
|
|
20
|
+
latitude: number;
|
|
21
|
+
longitude: number;
|
|
22
|
+
};
|
|
19
23
|
};
|
|
20
24
|
export type ObservedClientEvents = {
|
|
21
25
|
update: [
|
|
22
26
|
{
|
|
27
|
+
sample: ClientSample;
|
|
23
28
|
elapsedTimeInMs: number;
|
|
24
29
|
}
|
|
25
30
|
];
|
|
@@ -53,6 +58,11 @@ export type ObservedClientEvents = {
|
|
|
53
58
|
issue: [ClientIssue];
|
|
54
59
|
usingturn: [boolean];
|
|
55
60
|
usermediaerror: [string];
|
|
61
|
+
rejoined: [
|
|
62
|
+
{
|
|
63
|
+
lastJoined: number;
|
|
64
|
+
}
|
|
65
|
+
];
|
|
56
66
|
};
|
|
57
67
|
export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
|
|
58
68
|
on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
|
|
@@ -70,7 +80,8 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
|
|
|
70
80
|
sfuId?: string;
|
|
71
81
|
private readonly _peerConnections;
|
|
72
82
|
private _closed;
|
|
73
|
-
private
|
|
83
|
+
private _joinedEventAt?;
|
|
84
|
+
private _acceptedSamples;
|
|
74
85
|
private _timeZoneOffsetInHours?;
|
|
75
86
|
private _left?;
|
|
76
87
|
usingTURN: boolean;
|
|
@@ -110,6 +121,14 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
|
|
|
110
121
|
constructor(_model: ObservedClientModel, call: ObservedCall, appData: AppData);
|
|
111
122
|
getSfu<T extends Record<string, unknown> = Record<string, unknown>>(): ObservedSfu<T> | undefined;
|
|
112
123
|
get sfu(): ObservedSfu | undefined;
|
|
124
|
+
get coordinates(): {
|
|
125
|
+
latitude: number;
|
|
126
|
+
longitude: number;
|
|
127
|
+
} | undefined;
|
|
128
|
+
set coordinates(value: {
|
|
129
|
+
latitude: number;
|
|
130
|
+
longitude: number;
|
|
131
|
+
} | undefined);
|
|
113
132
|
get clientId(): string;
|
|
114
133
|
get roomId(): string;
|
|
115
134
|
get serviceId(): string;
|
|
@@ -124,7 +143,7 @@ export declare class ObservedClient<AppData extends Record<string, unknown> = Re
|
|
|
124
143
|
get engine(): Engine | undefined;
|
|
125
144
|
get operationSystem(): OperationSystem | undefined;
|
|
126
145
|
get platform(): Platform | undefined;
|
|
127
|
-
get
|
|
146
|
+
get acceptedSamples(): number;
|
|
128
147
|
get updated(): number;
|
|
129
148
|
get closed(): boolean;
|
|
130
149
|
get peerConnections(): ReadonlyMap<string, ObservedPeerConnection>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAChJ,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,OAAO,EAAE,SAAS,EAAe,MAAM,gBAAgB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIhE,MAAM,MAAM,mBAAmB,GAAE;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":"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"}
|
package/lib/ObservedClient.js
CHANGED
|
@@ -31,7 +31,7 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
31
31
|
this._updated = Date.now();
|
|
32
32
|
this._peerConnections = new Map();
|
|
33
33
|
this._closed = false;
|
|
34
|
-
this.
|
|
34
|
+
this._acceptedSamples = 0;
|
|
35
35
|
this.usingTURN = false;
|
|
36
36
|
this.availableOutgoingBitrate = 0;
|
|
37
37
|
this.availableIncomingBitrate = 0;
|
|
@@ -75,6 +75,12 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
75
75
|
return;
|
|
76
76
|
return this.call.observer.observedSfus.get(this.sfuId);
|
|
77
77
|
}
|
|
78
|
+
get coordinates() {
|
|
79
|
+
return this._model.coordinates;
|
|
80
|
+
}
|
|
81
|
+
set coordinates(value) {
|
|
82
|
+
this._model.coordinates = value;
|
|
83
|
+
}
|
|
78
84
|
get clientId() {
|
|
79
85
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
80
86
|
return this._model.clientId;
|
|
@@ -122,8 +128,8 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
122
128
|
get platform() {
|
|
123
129
|
return this._model.platform;
|
|
124
130
|
}
|
|
125
|
-
get
|
|
126
|
-
return this.
|
|
131
|
+
get acceptedSamples() {
|
|
132
|
+
return this._acceptedSamples;
|
|
127
133
|
}
|
|
128
134
|
get updated() {
|
|
129
135
|
return this._updated;
|
|
@@ -196,7 +202,7 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
196
202
|
throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
|
|
197
203
|
}
|
|
198
204
|
const now = Date.now();
|
|
199
|
-
++this.
|
|
205
|
+
++this._acceptedSamples;
|
|
200
206
|
for (const peerConnection of this._peerConnections.values()) {
|
|
201
207
|
if (peerConnection.closed)
|
|
202
208
|
continue;
|
|
@@ -285,6 +291,14 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
285
291
|
for (let _21 of (_p = sample.customCallEvents) !== null && _p !== void 0 ? _p : []) {
|
|
286
292
|
const { timestamp } = _21, callEvent = __rest(_21, ["timestamp"]);
|
|
287
293
|
switch (callEvent.name) {
|
|
294
|
+
case CallEventType_1.CallEventType.CLIENT_JOINED: {
|
|
295
|
+
const lastJoined = this._joinedEventAt;
|
|
296
|
+
this._joinedEventAt = timestamp !== null && timestamp !== void 0 ? timestamp : sample.timestamp;
|
|
297
|
+
if (lastJoined && this._joinedEventAt && lastJoined !== this._joinedEventAt) {
|
|
298
|
+
this.emit('rejoined', { lastJoined });
|
|
299
|
+
}
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
288
302
|
case CallEventType_1.CallEventType.CLIENT_LEFT: {
|
|
289
303
|
this._left = timestamp;
|
|
290
304
|
break;
|
|
@@ -600,8 +614,11 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
600
614
|
this.inboundAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
601
615
|
this.inboundVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
602
616
|
this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
|
|
617
|
+
// to make sure when sample is emitted it can be associated to this client
|
|
618
|
+
sample.clientId = this.clientId;
|
|
603
619
|
this._updated = now;
|
|
604
620
|
this.emit('update', {
|
|
621
|
+
sample,
|
|
605
622
|
elapsedTimeInMs,
|
|
606
623
|
});
|
|
607
624
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Middleware<T> = (input: T, next: (nextInput: T) => void) => void;
|
|
2
|
+
export interface Processor<T> {
|
|
3
|
+
process(value: T): void;
|
|
4
|
+
addMiddleware(...middlewares: Middleware<T>[]): Processor<T>;
|
|
5
|
+
removeMiddleware(...middlewares: Middleware<T>[]): Processor<T>;
|
|
6
|
+
}
|
|
7
|
+
export declare function createProcessor<T>(): Processor<T>;
|
|
8
|
+
//# sourceMappingURL=Middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../../src/common/Middleware.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAC3B,KAAK,EAAE,CAAC,EACR,IAAI,EAAE,CAAC,SAAS,EAAE,CAAC,KAAK,IAAI,KACxB,IAAI,CAAC;AAEV,MAAM,WAAW,SAAS,CAAC,CAAC;IAC3B,OAAO,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,aAAa,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IAC7D,gBAAgB,CAAC,GAAG,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;CAChE;AAED,wBAAgB,eAAe,CAAC,CAAC,KAC9B,SAAS,CAAC,CAAC,CAAC,CA2Cd"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createProcessor = void 0;
|
|
4
|
+
function createProcessor() {
|
|
5
|
+
const stack = [];
|
|
6
|
+
const result = {
|
|
7
|
+
addMiddleware: (...middlewares) => {
|
|
8
|
+
if (middlewares && 0 < middlewares.length) {
|
|
9
|
+
stack.push(...middlewares);
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
},
|
|
13
|
+
removeMiddleware: (...middlewares) => {
|
|
14
|
+
if (middlewares && 0 < middlewares.length) {
|
|
15
|
+
for (const process of middlewares) {
|
|
16
|
+
const index = stack.indexOf(process);
|
|
17
|
+
if (0 < index)
|
|
18
|
+
stack.splice(index, 1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
},
|
|
23
|
+
process: (value) => {
|
|
24
|
+
let prevIndex = -1;
|
|
25
|
+
const execute = (index, input) => {
|
|
26
|
+
if (index <= prevIndex) {
|
|
27
|
+
throw new Error('middleware must call next() only once!');
|
|
28
|
+
}
|
|
29
|
+
prevIndex = index;
|
|
30
|
+
const middleware = stack[index];
|
|
31
|
+
if (!middleware)
|
|
32
|
+
return;
|
|
33
|
+
const next = (nextInput) => execute(index + 1, nextInput);
|
|
34
|
+
return middleware(input, next);
|
|
35
|
+
};
|
|
36
|
+
return execute(0, value);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
exports.createProcessor = createProcessor;
|
|
@@ -13,10 +13,7 @@ export type ClientIssueMonitorEvents = {
|
|
|
13
13
|
minor: [ClientIssueMonitorEmittedIssueEvent];
|
|
14
14
|
critical: [ClientIssueMonitorEmittedIssueEvent];
|
|
15
15
|
};
|
|
16
|
-
export type ClientIssueMonitorConfig = {
|
|
17
|
-
detectUserMediaClientIssues?: boolean;
|
|
18
|
-
detectMediaTrackQualityLimitationClientIssues?: boolean;
|
|
19
|
-
};
|
|
16
|
+
export type ClientIssueMonitorConfig = {};
|
|
20
17
|
export declare interface ClientIssueMonitor {
|
|
21
18
|
on<U extends keyof ClientIssueMonitorEvents>(event: U, listener: (...args: ClientIssueMonitorEvents[U]) => void): this;
|
|
22
19
|
off<U extends keyof ClientIssueMonitorEvents>(event: U, listener: (...args: ClientIssueMonitorEvents[U]) => void): this;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientIssueMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/ClientIssueMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,MAAM,mCAAmC,GAAG,WAAW,GAAG;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,EAAE,CAAC;IACV,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,QAAQ,EAAE,CAAC,mCAAmC,CAAC,CAAC;CAEhD,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG
|
|
1
|
+
{"version":3,"file":"ClientIssueMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/ClientIssueMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,MAAM,MAAM,mCAAmC,GAAG,WAAW,GAAG;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CACf,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,EAAE,CAAC;IACV,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,KAAK,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC7C,QAAQ,EAAE,CAAC,mCAAmC,CAAC,CAAC;CAEhD,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,EAEtC,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,kBAAkB;IAC1C,EAAE,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACvH,GAAG,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACxH,IAAI,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACzH,IAAI,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACxG;AAED,qBAAa,kBAAmB,SAAQ,YAAY;aAGlC,MAAM,EAAE,wBAAwB;IAFjD,OAAO,CAAC,OAAO,CAAS;gBAEP,MAAM,GAAE,wBAA6B;IAM/C,OAAO,CAAC,IAAI,EAAE,YAAY;IAajC,OAAO,CAAC,UAAU;IAyBlB,IAAW,MAAM,YAEhB;IAEM,KAAK;CAMZ"}
|
package/package.json
CHANGED
package/src/ObservedCall.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { ObservedClient, ObservedClientModel } from './ObservedClient';
|
|
2
|
+
import { ObservedClient, ObservedClientEvents, ObservedClientModel } from './ObservedClient';
|
|
3
3
|
import { ObservedOutboundTrack } from './ObservedOutboundTrack';
|
|
4
4
|
import { Observer } from './Observer';
|
|
5
5
|
import { createClientJoinedEventReport } from './common/callEventReports';
|
|
6
6
|
import { PartialBy } from './common/utils';
|
|
7
7
|
import { CallEventReport } from '@observertc/report-schemas-js';
|
|
8
|
+
import { createProcessor } from './common/Middleware';
|
|
9
|
+
import { ClientSample } from '@observertc/sample-schemas-js';
|
|
10
|
+
import { ClientIssue } from './monitors/CallSummary';
|
|
11
|
+
|
|
12
|
+
type ClientIssueDetectionConfig = Pick<ClientIssue, 'severity'>;
|
|
8
13
|
|
|
9
14
|
export type ObservedCallModel = {
|
|
10
15
|
serviceId: string;
|
|
@@ -28,6 +33,8 @@ export declare interface ObservedCall {
|
|
|
28
33
|
export class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
29
34
|
public readonly created = Date.now();
|
|
30
35
|
|
|
36
|
+
public readonly processor = createProcessor<ClientSample>();
|
|
37
|
+
|
|
31
38
|
private readonly _clients = new Map<string, ObservedClient>();
|
|
32
39
|
|
|
33
40
|
public readonly sfuStreamIdToOutboundAudioTrack = new Map<string | number, ObservedOutboundTrack<'audio'>>();
|
|
@@ -100,21 +107,39 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
100
107
|
});
|
|
101
108
|
}
|
|
102
109
|
|
|
103
|
-
public createClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(config: ObservedClientModel & {
|
|
110
|
+
public createClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(config: ObservedClientModel & {
|
|
111
|
+
appData: ClientAppData,
|
|
112
|
+
generateClientJoinedReport?: boolean,
|
|
113
|
+
joined?: number,
|
|
114
|
+
detectIssues?: {
|
|
115
|
+
rejoin: ClientIssue['severity'] | ClientIssueDetectionConfig,
|
|
116
|
+
},
|
|
117
|
+
}) {
|
|
104
118
|
if (this._closed) throw new Error(`Call ${this.callId} is closed`);
|
|
105
119
|
|
|
106
|
-
const {
|
|
120
|
+
const {
|
|
121
|
+
appData,
|
|
122
|
+
generateClientJoinedReport,
|
|
123
|
+
joined = Date.now(),
|
|
124
|
+
detectIssues = {
|
|
125
|
+
rejoin: 'minor'
|
|
126
|
+
},
|
|
127
|
+
...model
|
|
128
|
+
} = config;
|
|
107
129
|
|
|
108
130
|
const result = new ObservedClient(model, this, appData);
|
|
109
|
-
const onUpdate = () => {
|
|
131
|
+
const onUpdate = ({ sample }: { sample: ClientSample }) => {
|
|
110
132
|
this._updated = Date.now();
|
|
111
133
|
this.emit('update');
|
|
134
|
+
|
|
135
|
+
this.processor.process(sample);
|
|
112
136
|
};
|
|
113
137
|
|
|
114
138
|
result.once('close', () => {
|
|
115
139
|
result.off('update', onUpdate);
|
|
116
140
|
this._clients.delete(result.clientId);
|
|
117
141
|
});
|
|
142
|
+
|
|
118
143
|
result.on('update', onUpdate);
|
|
119
144
|
this._clients.set(result.clientId, result);
|
|
120
145
|
|
|
@@ -131,6 +156,25 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
131
156
|
));
|
|
132
157
|
}
|
|
133
158
|
|
|
159
|
+
if (detectIssues?.rejoin) {
|
|
160
|
+
const issueBaseConfig = typeof detectIssues.rejoin === 'object' ? detectIssues.rejoin : {
|
|
161
|
+
severity: detectIssues.rejoin
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const rejoinedClientIssueListener = (event: ObservedClientEvents['rejoined'][0]) => {
|
|
165
|
+
event.lastJoined;
|
|
166
|
+
result.addIssue({
|
|
167
|
+
timestamp: Date.now(),
|
|
168
|
+
...issueBaseConfig,
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
result.once('close', () => {
|
|
173
|
+
result.off('rejoined', rejoinedClientIssueListener);
|
|
174
|
+
});
|
|
175
|
+
result.on('rejoined', rejoinedClientIssueListener);
|
|
176
|
+
}
|
|
177
|
+
|
|
134
178
|
this.emit('newclient', result);
|
|
135
179
|
|
|
136
180
|
return result;
|
package/src/ObservedClient.ts
CHANGED
|
@@ -23,10 +23,15 @@ export type ObservedClientModel= {
|
|
|
23
23
|
engine?: Engine,
|
|
24
24
|
platform?: Platform,
|
|
25
25
|
browser?: Browser,
|
|
26
|
+
coordinates?: {
|
|
27
|
+
latitude: number;
|
|
28
|
+
longitude: number;
|
|
29
|
+
},
|
|
26
30
|
};
|
|
27
31
|
|
|
28
32
|
export type ObservedClientEvents = {
|
|
29
33
|
update: [{
|
|
34
|
+
sample: ClientSample,
|
|
30
35
|
elapsedTimeInMs: number,
|
|
31
36
|
}],
|
|
32
37
|
close: [],
|
|
@@ -51,6 +56,9 @@ export type ObservedClientEvents = {
|
|
|
51
56
|
issue: [ClientIssue],
|
|
52
57
|
usingturn: [boolean],
|
|
53
58
|
usermediaerror: [string],
|
|
59
|
+
rejoined: [{
|
|
60
|
+
lastJoined: number,
|
|
61
|
+
}],
|
|
54
62
|
};
|
|
55
63
|
|
|
56
64
|
export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
|
|
@@ -71,7 +79,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
71
79
|
|
|
72
80
|
private _closed = false;
|
|
73
81
|
|
|
74
|
-
private
|
|
82
|
+
private _joinedEventAt?: number;
|
|
83
|
+
private _acceptedSamples = 0;
|
|
75
84
|
private _timeZoneOffsetInHours?: number;
|
|
76
85
|
private _left?: number;
|
|
77
86
|
|
|
@@ -137,6 +146,14 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
137
146
|
return this.call.observer.observedSfus.get(this.sfuId);
|
|
138
147
|
}
|
|
139
148
|
|
|
149
|
+
public get coordinates() {
|
|
150
|
+
return this._model.coordinates;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public set coordinates(value: { latitude: number; longitude: number } | undefined) {
|
|
154
|
+
this._model.coordinates = value;
|
|
155
|
+
}
|
|
156
|
+
|
|
140
157
|
public get clientId(): string {
|
|
141
158
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
142
159
|
return this._model.clientId!;
|
|
@@ -198,8 +215,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
198
215
|
return this._model.platform;
|
|
199
216
|
}
|
|
200
217
|
|
|
201
|
-
public get
|
|
202
|
-
return this.
|
|
218
|
+
public get acceptedSamples() {
|
|
219
|
+
return this._acceptedSamples;
|
|
203
220
|
}
|
|
204
221
|
|
|
205
222
|
public get updated() {
|
|
@@ -296,7 +313,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
296
313
|
}
|
|
297
314
|
const now = Date.now();
|
|
298
315
|
|
|
299
|
-
++this.
|
|
316
|
+
++this._acceptedSamples;
|
|
300
317
|
|
|
301
318
|
for (const peerConnection of this._peerConnections.values()) {
|
|
302
319
|
if (peerConnection.closed) continue;
|
|
@@ -472,6 +489,16 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
472
489
|
|
|
473
490
|
for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
|
|
474
491
|
switch (callEvent.name) {
|
|
492
|
+
case CallEventType.CLIENT_JOINED: {
|
|
493
|
+
const lastJoined = this._joinedEventAt;
|
|
494
|
+
|
|
495
|
+
this._joinedEventAt = timestamp ?? sample.timestamp;
|
|
496
|
+
|
|
497
|
+
if (lastJoined && this._joinedEventAt && lastJoined !== this._joinedEventAt) {
|
|
498
|
+
this.emit('rejoined', { lastJoined });
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
475
502
|
case CallEventType.CLIENT_LEFT: {
|
|
476
503
|
this._left = timestamp;
|
|
477
504
|
break;
|
|
@@ -903,8 +930,12 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
903
930
|
|
|
904
931
|
this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
|
|
905
932
|
|
|
933
|
+
// to make sure when sample is emitted it can be associated to this client
|
|
934
|
+
sample.clientId = this.clientId;
|
|
935
|
+
|
|
906
936
|
this._updated = now;
|
|
907
937
|
this.emit('update', {
|
|
938
|
+
sample,
|
|
908
939
|
elapsedTimeInMs,
|
|
909
940
|
});
|
|
910
941
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type Middleware<T> = (
|
|
2
|
+
input: T,
|
|
3
|
+
next: (nextInput: T) => void,
|
|
4
|
+
) => void;
|
|
5
|
+
|
|
6
|
+
export interface Processor<T> {
|
|
7
|
+
process(value: T): void;
|
|
8
|
+
addMiddleware(...middlewares: Middleware<T>[]): Processor<T>;
|
|
9
|
+
removeMiddleware(...middlewares: Middleware<T>[]): Processor<T>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createProcessor<T>(
|
|
13
|
+
): Processor<T> {
|
|
14
|
+
const stack: Middleware<T>[] = [];
|
|
15
|
+
const result: Processor<T> = {
|
|
16
|
+
addMiddleware: (...middlewares: Middleware<T>[]) => {
|
|
17
|
+
if (middlewares && 0 < middlewares.length) {
|
|
18
|
+
stack.push(...middlewares);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return result;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
removeMiddleware: (...middlewares: Middleware<T>[]) => {
|
|
25
|
+
if (middlewares && 0 < middlewares.length) {
|
|
26
|
+
for (const process of middlewares) {
|
|
27
|
+
const index = stack.indexOf(process);
|
|
28
|
+
|
|
29
|
+
if (0 < index) stack.splice(index, 1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return result;
|
|
34
|
+
},
|
|
35
|
+
process: (value: T) => {
|
|
36
|
+
let prevIndex = -1;
|
|
37
|
+
const execute = (index: number, input: T): void => {
|
|
38
|
+
if (index <= prevIndex) {
|
|
39
|
+
throw new Error('middleware must call next() only once!');
|
|
40
|
+
}
|
|
41
|
+
prevIndex = index;
|
|
42
|
+
const middleware = stack[index];
|
|
43
|
+
|
|
44
|
+
if (!middleware) return;
|
|
45
|
+
|
|
46
|
+
const next = (nextInput: T) => execute(index + 1, nextInput);
|
|
47
|
+
|
|
48
|
+
return middleware(input, next);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return execute(0, value);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
@@ -18,8 +18,7 @@ export type ClientIssueMonitorEvents = {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export type ClientIssueMonitorConfig = {
|
|
21
|
-
|
|
22
|
-
detectMediaTrackQualityLimitationClientIssues?: boolean;
|
|
21
|
+
// empty
|
|
23
22
|
}
|
|
24
23
|
|
|
25
24
|
export declare interface ClientIssueMonitor {
|