@observertc/observer-js 0.40.11-beta → 0.40.12
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/README.md +52 -24
- package/lib/ObservedClient.d.ts +8 -0
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +10 -0
- package/lib/ObservedOutboundTrack.d.ts +1 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +7 -0
- package/lib/Observer.d.ts +4 -2
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +4 -4
- package/lib/common/CallEventType.d.ts +2 -1
- package/lib/common/CallEventType.d.ts.map +1 -1
- package/lib/common/CallEventType.js +2 -1
- package/lib/monitors/CallSummary.d.ts +4 -0
- package/lib/monitors/CallSummary.d.ts.map +1 -1
- package/lib/monitors/CallSummaryMonitor.d.ts +8 -1
- package/lib/monitors/CallSummaryMonitor.d.ts.map +1 -1
- package/lib/monitors/CallSummaryMonitor.js +55 -1
- package/lib/monitors/TurnUsageMonitor.d.ts +2 -0
- package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -1
- package/lib/monitors/TurnUsageMonitor.js +9 -0
- package/package.json +1 -1
- package/src/ObservedClient.ts +20 -0
- package/src/ObservedOutboundTrack.ts +9 -0
- package/src/Observer.ts +13 -7
- package/src/common/CallEventType.ts +1 -1
- package/src/monitors/CallSummary.ts +5 -0
- package/src/monitors/CallSummaryMonitor.ts +76 -4
- package/src/monitors/TurnUsageMonitor.ts +13 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Server side component for monitoring WebRTC
|
|
1
|
+
Server side component for monitoring WebRTC applications and services
|
|
2
2
|
---
|
|
3
3
|
|
|
4
4
|
Table of Contents:
|
|
@@ -6,9 +6,7 @@ Table of Contents:
|
|
|
6
6
|
* [Quick Start](#quick-start)
|
|
7
7
|
* [Configurations](#configurations)
|
|
8
8
|
* [NPM package](#npm-package)
|
|
9
|
-
* [API docs](#api-docs)
|
|
10
9
|
* [Schemas](#schemas)
|
|
11
|
-
* [Getting Involved](#getting-involved)
|
|
12
10
|
* [License](#license)
|
|
13
11
|
|
|
14
12
|
## Qucik Start
|
|
@@ -25,29 +23,23 @@ Use it in your server side NodeJS app.
|
|
|
25
23
|
import { createObserver, ClientSample } from "@observertc/observer-js";
|
|
26
24
|
|
|
27
25
|
const observer = createObserver({
|
|
28
|
-
|
|
26
|
+
defaultServiceId: 'my-service-name',
|
|
27
|
+
defaultMediaUnitId: 'my-reporting-component',
|
|
29
28
|
});
|
|
30
29
|
|
|
31
|
-
const
|
|
30
|
+
const observedCall = observer.createObservedCall({
|
|
32
31
|
roomId: 'roomId',
|
|
33
32
|
callId: 'room-session-id',
|
|
34
|
-
clientId: 'reporting-client-id',
|
|
35
33
|
});
|
|
36
34
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
observer.addEvaluator(async context => {
|
|
42
|
-
const { endedCalls } = context;
|
|
43
|
-
|
|
44
|
-
// Observe call durations
|
|
45
|
-
for (const endedCall of endedCalls) {
|
|
46
|
-
const elapsedTimeInMins = (endedCall.ended - Number(endedCall.started)) / (60 * 1000);
|
|
47
|
-
console.log(`Call ${endedCall.callId} duration was ${elapsedTimeInMins} minutes`);
|
|
48
|
-
}
|
|
35
|
+
const observedClient = observedCall.createObservedClient({
|
|
36
|
+
clientId: 'client-id',
|
|
37
|
+
mediaUnitId: 'media-unit-id',
|
|
49
38
|
});
|
|
50
39
|
|
|
40
|
+
const clientSample: ClientSample; // Receive your samples, for example, from a WebSocket
|
|
41
|
+
|
|
42
|
+
observedClient.accept(clientSample);
|
|
51
43
|
```
|
|
52
44
|
|
|
53
45
|
The above example do as follows:
|
|
@@ -55,9 +47,49 @@ The above example do as follows:
|
|
|
55
47
|
2. create a client source object to accept client samples
|
|
56
48
|
3. add an evaluator process to evaluate ended calls
|
|
57
49
|
|
|
58
|
-
|
|
50
|
+
### Get a Summary of a call when it ends
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
|
|
54
|
+
const monitor = observer.createCallSummaryMonitor('summary', (summary) => {
|
|
55
|
+
console.log('Call Summary', summary);
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### How Many Clients are using TURN?
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
const monitor = observer.createTurnUsageMonitor('turn', (turn) => {
|
|
63
|
+
console.log('TURN', turn);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// at any point of time you can get the current state of the turn usage
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
console.log('Currently ', monitor.clients.size, 'clients are using TURN');
|
|
69
|
+
|
|
70
|
+
// you can get the incoming and outgoing bytes of the TURN server
|
|
71
|
+
console.log(`${YOUR_TURN_SERVER_ADDRESS} usage:`, monitor.getUsage(YOUR_TURN_SERVER_ADDRESS));
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Monitor Calls and Clients as they updated
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
observer.on('newcall', (call) => {
|
|
79
|
+
call.on('update', () => {
|
|
80
|
+
console.log('Call Updated', call.callId);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
call.on('newclient', (client) => {
|
|
84
|
+
|
|
85
|
+
client.on('update', () => {
|
|
86
|
+
console.log('Client Updated', client.clientId);
|
|
87
|
+
|
|
88
|
+
console.log(`The avaialble incoming bitrate for the client ${client.clientId} is: ${client.availableIncomingBitrate}`)
|
|
89
|
+
});
|
|
90
|
+
})
|
|
91
|
+
});
|
|
92
|
+
```
|
|
61
93
|
|
|
62
94
|
## NPM package
|
|
63
95
|
|
|
@@ -69,10 +101,6 @@ https://www.npmjs.com/package/@observertc/observer-js
|
|
|
69
101
|
https://github.com/observertc/schemas
|
|
70
102
|
|
|
71
103
|
|
|
72
|
-
## Getting Involved
|
|
73
|
-
|
|
74
|
-
The repository is open for contributions.
|
|
75
|
-
|
|
76
104
|
## License
|
|
77
105
|
|
|
78
106
|
Apache-2.0
|
package/lib/ObservedClient.d.ts
CHANGED
|
@@ -4,6 +4,13 @@ import { ObservedCall } from './ObservedCall';
|
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
6
6
|
import { ObservedSfu } from './ObservedSfu';
|
|
7
|
+
export interface ClientIssue {
|
|
8
|
+
severity: 'critical' | 'major' | 'minor';
|
|
9
|
+
timestamp: number;
|
|
10
|
+
description?: string;
|
|
11
|
+
peerConnectionId?: string;
|
|
12
|
+
trackId?: string;
|
|
13
|
+
}
|
|
7
14
|
export type ObservedClientModel = {
|
|
8
15
|
clientId: string;
|
|
9
16
|
mediaUnitId: string;
|
|
@@ -47,6 +54,7 @@ export type ObservedClientEvents = {
|
|
|
47
54
|
remoteCandidate: IceRemoteCandidate;
|
|
48
55
|
}
|
|
49
56
|
];
|
|
57
|
+
issue: [ClientIssue];
|
|
50
58
|
usingturn: [boolean];
|
|
51
59
|
usermediaerror: [string];
|
|
52
60
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ObservedClient.d.ts","sourceRoot":"","sources":["../src/ObservedClient.ts"],"names":[],"mappings":"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"}
|
package/lib/ObservedClient.js
CHANGED
|
@@ -229,6 +229,16 @@ class ObservedClient extends events_1.EventEmitter {
|
|
|
229
229
|
this._left = timestamp;
|
|
230
230
|
break;
|
|
231
231
|
}
|
|
232
|
+
case CallEventType_1.CallEventType.CLIENT_ISSUE: {
|
|
233
|
+
const severity = callEvent.value ? callEvent.value : 'minor';
|
|
234
|
+
this.emit('issue', {
|
|
235
|
+
severity,
|
|
236
|
+
timestamp: timestamp !== null && timestamp !== void 0 ? timestamp : Date.now(),
|
|
237
|
+
description: callEvent.message,
|
|
238
|
+
peerConnectionId: callEvent.peerConnectionId,
|
|
239
|
+
trackId: callEvent.mediaTrackId,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
232
242
|
}
|
|
233
243
|
this.reports.addCallEventReport(Object.assign({ serviceId: this.serviceId, mediaUnitId: this.mediaUnitId, roomId: this.roomId, callId: this.callId, clientId: this.clientId, userId: this.userId, timestamp: timestamp !== null && timestamp !== void 0 ? timestamp : Date.now() }, callEvent));
|
|
234
244
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedOutboundTrack.d.ts","sourceRoot":"","sources":["../src/ObservedOutboundTrack.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ObservedOutboundTrack.d.ts","sourceRoot":"","sources":["../src/ObservedOutboundTrack.ts"],"names":[],"mappings":"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"}
|
|
@@ -112,6 +112,13 @@ class ObservedOutboundTrack extends events_1.EventEmitter {
|
|
|
112
112
|
if ((videoSample === null || videoSample === void 0 ? void 0 : videoSample.framesSent) && (lastVideoStats === null || lastVideoStats === void 0 ? void 0 : lastVideoStats.framesSent) && lastVideoStats.framesSent < videoSample.framesSent) {
|
|
113
113
|
deltaSentFrames = videoSample.framesSent - lastVideoStats.framesSent;
|
|
114
114
|
}
|
|
115
|
+
if (videoSample.qualityLimitationReason && (lastVideoStats === null || lastVideoStats === void 0 ? void 0 : lastVideoStats.qualityLimitationReason) !== videoSample.qualityLimitationReason) {
|
|
116
|
+
this.emit('qualitylimitationchanged', videoSample.qualityLimitationReason);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (this.kind === 'audio') {
|
|
120
|
+
// const audioSample = sample as OutboundAudioTrack;
|
|
121
|
+
// const lastAudioStats = lastStat as OutboundAudioTrack | undefined;
|
|
115
122
|
}
|
|
116
123
|
const stats = Object.assign(Object.assign({}, sample), { rttInMs,
|
|
117
124
|
bitrate, ssrc: sample.ssrc, deltaLostPackets,
|
package/lib/Observer.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { EventEmitter } from 'events';
|
|
|
5
5
|
import { PartialBy } from './common/utils';
|
|
6
6
|
import { ObserverSinkContext } from './common/types';
|
|
7
7
|
import { ObservedSfu, ObservedSfuModel } from './ObservedSfu';
|
|
8
|
-
import { CallSummaryMonitor } from './monitors/CallSummaryMonitor';
|
|
8
|
+
import { CallSummaryMonitor, CallSummaryMonitorConfig } from './monitors/CallSummaryMonitor';
|
|
9
9
|
import { TurnUsageMonitor } from './monitors/TurnUsageMonitor';
|
|
10
10
|
export type ObserverEvents = {
|
|
11
11
|
'newcall': [ObservedCall];
|
|
@@ -51,9 +51,11 @@ export declare class Observer extends EventEmitter {
|
|
|
51
51
|
createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(config: PartialBy<ObservedCallModel, 'serviceId'> & {
|
|
52
52
|
appData: T;
|
|
53
53
|
started?: number;
|
|
54
|
+
reportCallStarted?: boolean;
|
|
55
|
+
reportCallEnded?: boolean;
|
|
54
56
|
}): ObservedCall<T>;
|
|
55
57
|
createObservedSfu<AppData extends Record<string, unknown> = Record<string, unknown>>(model: ObservedSfuModel, appData: AppData): ObservedSfu<AppData>;
|
|
56
|
-
createCallSummaryMonitor(options?: {
|
|
58
|
+
createCallSummaryMonitor(options?: CallSummaryMonitorConfig & {
|
|
57
59
|
timeoutAfterCallClose?: number;
|
|
58
60
|
}): CallSummaryMonitor;
|
|
59
61
|
createTurnUsageMonitor(): TurnUsageMonitor;
|
package/lib/Observer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":"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"}
|
package/lib/Observer.js
CHANGED
|
@@ -65,7 +65,7 @@ class Observer extends events_1.EventEmitter {
|
|
|
65
65
|
if (this._closed) {
|
|
66
66
|
throw new Error('Attempted to create a call source on a closed observer');
|
|
67
67
|
}
|
|
68
|
-
const { appData, started = Date.now() } = config, model = __rest(config, ["appData", "started"]);
|
|
68
|
+
const { appData, started = Date.now(), reportCallEnded = true, reportCallStarted = true } = config, model = __rest(config, ["appData", "started", "reportCallEnded", "reportCallStarted"]);
|
|
69
69
|
const call = new ObservedCall_1.ObservedCall(Object.assign(Object.assign({}, model), { serviceId: this.config.defaultServiceId }), this, appData);
|
|
70
70
|
if (this._closed)
|
|
71
71
|
throw new Error('Cannot create an observed call on a closed observer');
|
|
@@ -73,10 +73,10 @@ class Observer extends events_1.EventEmitter {
|
|
|
73
73
|
throw new Error(`Observed Call with id ${call.callId} already exists`);
|
|
74
74
|
call.once('close', () => {
|
|
75
75
|
this._observedCalls.delete(call.callId);
|
|
76
|
-
this.reports.addCallEventReport((0, callEventReports_1.createCallEndedEventReport)(call.serviceId, call.roomId, call.callId, Date.now()));
|
|
76
|
+
reportCallEnded && this.reports.addCallEventReport((0, callEventReports_1.createCallEndedEventReport)(call.serviceId, call.roomId, call.callId, Date.now()));
|
|
77
77
|
});
|
|
78
78
|
this._observedCalls.set(call.callId, call);
|
|
79
|
-
this.reports.addCallEventReport((0, callEventReports_1.createCallStartedEventReport)(call.serviceId, call.roomId, call.callId, started));
|
|
79
|
+
reportCallStarted && this.reports.addCallEventReport((0, callEventReports_1.createCallStartedEventReport)(call.serviceId, call.roomId, call.callId, started));
|
|
80
80
|
this.emit('newcall', call);
|
|
81
81
|
return call;
|
|
82
82
|
}
|
|
@@ -102,7 +102,7 @@ class Observer extends events_1.EventEmitter {
|
|
|
102
102
|
const existingMonitor = this._monitors.get(CallSummaryMonitor_1.CallSummaryMonitor.name);
|
|
103
103
|
if (existingMonitor)
|
|
104
104
|
return existingMonitor;
|
|
105
|
-
const monitor = new CallSummaryMonitor_1.CallSummaryMonitor();
|
|
105
|
+
const monitor = new CallSummaryMonitor_1.CallSummaryMonitor(options);
|
|
106
106
|
const onNewCall = (call) => {
|
|
107
107
|
monitor.addCall(call);
|
|
108
108
|
call.once('close', () => {
|
|
@@ -17,6 +17,7 @@ export declare enum CallEventType {
|
|
|
17
17
|
DATA_CHANNEL_CLOSED = "DATA_CHANNEL_CLOSED",
|
|
18
18
|
DATA_CHANNEL_ERROR = "DATA_CHANNEL_ERROR",
|
|
19
19
|
NEGOTIATION_NEEDED = "NEGOTIATION_NEEDED",
|
|
20
|
-
SIGNALING_STATE_CHANGE = "SIGNALING_STATE_CHANGE"
|
|
20
|
+
SIGNALING_STATE_CHANGE = "SIGNALING_STATE_CHANGE",
|
|
21
|
+
CLIENT_ISSUE = "CLIENT_ISSUE"
|
|
21
22
|
}
|
|
22
23
|
//# sourceMappingURL=CallEventType.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CallEventType.d.ts","sourceRoot":"","sources":["../../src/common/CallEventType.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CallEventType.d.ts","sourceRoot":"","sources":["../../src/common/CallEventType.ts"],"names":[],"mappings":"AACA,oBAAY,aAAa;IACxB,YAAY,iBAAiB;IAC7B,UAAU,eAAe;IACzB,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAC3B,sBAAsB,2BAA2B;IACjD,sBAAsB,2BAA2B;IACjD,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;IAC3C,mBAAmB,wBAAwB;IAC3C,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;IAC3C,2BAA2B,gCAAgC;IAC3D,6BAA6B,kCAAkC;IAC/D,4BAA4B,iCAAiC;IAC7D,iBAAiB,sBAAsB;IACvC,mBAAmB,wBAAwB;IAC3C,kBAAkB,uBAAuB;IACzC,kBAAkB,uBAAuB;IACzC,sBAAsB,2BAA2B;IACjD,YAAY,iBAAiB;CAC7B"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// eslint-disable-next-line no-shadow
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.CallEventType = void 0;
|
|
4
|
+
// eslint-disable-next-line no-shadow
|
|
5
5
|
var CallEventType;
|
|
6
6
|
(function (CallEventType) {
|
|
7
7
|
CallEventType["CALL_STARTED"] = "CALL_STARTED";
|
|
@@ -23,4 +23,5 @@ var CallEventType;
|
|
|
23
23
|
CallEventType["DATA_CHANNEL_ERROR"] = "DATA_CHANNEL_ERROR";
|
|
24
24
|
CallEventType["NEGOTIATION_NEEDED"] = "NEGOTIATION_NEEDED";
|
|
25
25
|
CallEventType["SIGNALING_STATE_CHANGE"] = "SIGNALING_STATE_CHANGE";
|
|
26
|
+
CallEventType["CLIENT_ISSUE"] = "CLIENT_ISSUE";
|
|
26
27
|
})(CallEventType = exports.CallEventType || (exports.CallEventType = {}));
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import { ClientIssue } from '../ObservedClient';
|
|
1
2
|
export interface ClientSummary {
|
|
2
3
|
clientId: string;
|
|
3
4
|
mediaUnitId: string;
|
|
4
5
|
userId?: string;
|
|
5
6
|
joined: number;
|
|
7
|
+
left?: number;
|
|
6
8
|
durationInMs: number;
|
|
7
9
|
avgOutboundAudioBitrate: number;
|
|
8
10
|
avgOutboundVideoBitrate: number;
|
|
9
11
|
avgInboundAudioBitrate: number;
|
|
10
12
|
avgInboundVideoBitrate: number;
|
|
11
13
|
ewmaRttInMs: number;
|
|
14
|
+
usedTurn: boolean;
|
|
15
|
+
issues: ClientIssue[];
|
|
12
16
|
}
|
|
13
17
|
export interface CallSummary {
|
|
14
18
|
serviceId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CallSummary.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummary.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"CallSummary.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,WAAW,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,aAAa,EAAE,CAAC;CACzB"}
|
|
@@ -6,6 +6,10 @@ export type CallSummaryMonitorEvents = {
|
|
|
6
6
|
close: [];
|
|
7
7
|
summary: [CallSummary];
|
|
8
8
|
};
|
|
9
|
+
export type CallSummaryMonitorConfig = {
|
|
10
|
+
detectUserMediaIssues?: boolean;
|
|
11
|
+
detectMediaTrackQualityLimitationIssues?: boolean;
|
|
12
|
+
};
|
|
9
13
|
export declare interface CallSummaryMonitor {
|
|
10
14
|
on<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
|
|
11
15
|
off<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
|
|
@@ -13,11 +17,14 @@ export declare interface CallSummaryMonitor {
|
|
|
13
17
|
emit<U extends keyof CallSummaryMonitorEvents>(event: U, ...args: CallSummaryMonitorEvents[U]): boolean;
|
|
14
18
|
}
|
|
15
19
|
export declare class CallSummaryMonitor extends EventEmitter {
|
|
20
|
+
readonly config: CallSummaryMonitorConfig;
|
|
16
21
|
private readonly _summaries;
|
|
17
22
|
private _closed;
|
|
18
|
-
constructor();
|
|
23
|
+
constructor(config?: CallSummaryMonitorConfig);
|
|
19
24
|
addCall(call: ObservedCall): void;
|
|
20
25
|
private _addClient;
|
|
26
|
+
private _addPeerConnection;
|
|
27
|
+
private _addOutboundVideoTrack;
|
|
21
28
|
takeSummary(callId: string): CallSummary | undefined;
|
|
22
29
|
get closed(): boolean;
|
|
23
30
|
close(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CallSummaryMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummaryMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"CallSummaryMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummaryMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,WAAW,EAAiB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAK/C,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,EAAE,CAAC;IACV,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC;CACvB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACtC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,uCAAuC,CAAC,EAAE,OAAO,CAAC;CAClD,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;aAKlC,MAAM,EAAE,wBAAwB;IAJjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAE7D,OAAO,CAAC,OAAO,CAAS;gBAEP,MAAM,GAAE,wBAA6B;IAK/C,OAAO,CAAC,IAAI,EAAE,YAAY;IAyBjC,OAAO,CAAC,UAAU;IAuElB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,sBAAsB;IAmBvB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAU3D,IAAW,MAAM,YAEhB;IAEM,KAAK;CAMZ"}
|
|
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CallSummaryMonitor = void 0;
|
|
4
4
|
const events_1 = require("events");
|
|
5
5
|
class CallSummaryMonitor extends events_1.EventEmitter {
|
|
6
|
-
constructor() {
|
|
6
|
+
constructor(config = {}) {
|
|
7
7
|
super();
|
|
8
|
+
this.config = config;
|
|
8
9
|
this._summaries = new Map();
|
|
9
10
|
this._closed = false;
|
|
10
11
|
}
|
|
@@ -44,6 +45,8 @@ class CallSummaryMonitor extends events_1.EventEmitter {
|
|
|
44
45
|
ewmaRttInMs: 0,
|
|
45
46
|
joined: client.created,
|
|
46
47
|
userId: client.userId,
|
|
48
|
+
usedTurn: false,
|
|
49
|
+
issues: [],
|
|
47
50
|
};
|
|
48
51
|
callSummary.clients.push(clientSummary);
|
|
49
52
|
const updateClient = () => {
|
|
@@ -51,7 +54,29 @@ class CallSummaryMonitor extends events_1.EventEmitter {
|
|
|
51
54
|
clientSummary.ewmaRttInMs = (clientSummary.ewmaRttInMs * 0.9) + (client.avgRttInMs * 0.1);
|
|
52
55
|
}
|
|
53
56
|
};
|
|
57
|
+
const onUsingTurn = (usingTurn) => {
|
|
58
|
+
clientSummary.usedTurn || (clientSummary.usedTurn = usingTurn);
|
|
59
|
+
};
|
|
60
|
+
const onIssue = (issue) => {
|
|
61
|
+
clientSummary.issues.push(issue);
|
|
62
|
+
};
|
|
63
|
+
const onUserMediaError = (error) => {
|
|
64
|
+
if (!this.config.detectUserMediaIssues)
|
|
65
|
+
return;
|
|
66
|
+
// maybe the client also sned this issue, in which case the timestamp can be more accurate
|
|
67
|
+
const alreadyDetected = clientSummary.issues.find((issue) => issue.severity === 'critical' && issue.description === error);
|
|
68
|
+
!alreadyDetected && clientSummary.issues.push({
|
|
69
|
+
severity: 'critical',
|
|
70
|
+
timestamp: Date.now(),
|
|
71
|
+
description: error,
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const onNewPeerConnection = (peerConnection) => this._addPeerConnection(clientSummary, peerConnection);
|
|
54
75
|
client.on('update', updateClient);
|
|
76
|
+
client.on('usingturn', onUsingTurn);
|
|
77
|
+
client.on('issue', onIssue);
|
|
78
|
+
client.on('usermediaerror', onUserMediaError);
|
|
79
|
+
client.on('newpeerconnection', onNewPeerConnection);
|
|
55
80
|
client.once('close', () => {
|
|
56
81
|
const elapsedTimeInS = (Date.now() - client.created) / 1000;
|
|
57
82
|
clientSummary.avgInboundAudioBitrate = (client.totalReceivedBytes * 8) / elapsedTimeInS;
|
|
@@ -60,7 +85,36 @@ class CallSummaryMonitor extends events_1.EventEmitter {
|
|
|
60
85
|
clientSummary.avgOutboundVideoBitrate = (client.totalSentBytes * 8) / elapsedTimeInS;
|
|
61
86
|
clientSummary.durationInMs = elapsedTimeInS * 1000;
|
|
62
87
|
client.off('update', updateClient);
|
|
88
|
+
client.off('usingturn', onUsingTurn);
|
|
89
|
+
client.off('issue', onIssue);
|
|
90
|
+
client.off('usermediaerror', onUserMediaError);
|
|
91
|
+
client.off('newpeerconnection', onNewPeerConnection);
|
|
92
|
+
callSummary.durationInMs += clientSummary.durationInMs;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
_addPeerConnection(clientSummary, peerConnection) {
|
|
96
|
+
const onOutboundVideoTrack = (track) => this._addOutboundVideoTrack(clientSummary, track);
|
|
97
|
+
peerConnection.on('newoutboundvideotrack', onOutboundVideoTrack);
|
|
98
|
+
peerConnection.once('close', () => {
|
|
99
|
+
peerConnection.off('newoutboundvideotrack', onOutboundVideoTrack);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
_addOutboundVideoTrack(clientSummary, track) {
|
|
103
|
+
const onQualityLimitationChanged = (reason) => {
|
|
104
|
+
if (!this.config.detectMediaTrackQualityLimitationIssues)
|
|
105
|
+
return;
|
|
106
|
+
clientSummary.issues.push({
|
|
107
|
+
severity: 'minor',
|
|
108
|
+
timestamp: Date.now(),
|
|
109
|
+
description: reason,
|
|
110
|
+
peerConnectionId: track.peerConnectionId,
|
|
111
|
+
trackId: track.trackId,
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
track.once('close', () => {
|
|
115
|
+
track.off('qualitylimitationchanged', onQualityLimitationChanged);
|
|
63
116
|
});
|
|
117
|
+
track.on('qualitylimitationchanged', onQualityLimitationChanged);
|
|
64
118
|
}
|
|
65
119
|
takeSummary(callId) {
|
|
66
120
|
if (this.closed)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { EventEmitter } from 'events';
|
|
3
3
|
import { ObservedPeerConnection } from '../ObservedPeerConnection';
|
|
4
|
+
import { ObservedClient } from '../ObservedClient';
|
|
4
5
|
export type TurnUsageMonitorEvents = {
|
|
5
6
|
close: [];
|
|
6
7
|
'newturnip': [string];
|
|
@@ -31,6 +32,7 @@ export declare class TurnUsageMonitor extends EventEmitter {
|
|
|
31
32
|
get turnIps(): string[];
|
|
32
33
|
get peerConnections(): ObservedPeerConnection[];
|
|
33
34
|
getUsage(turnIp: string): TurnUsage | undefined;
|
|
35
|
+
get clients(): ReadonlyMap<string, ObservedClient>;
|
|
34
36
|
get closed(): boolean;
|
|
35
37
|
close(): void;
|
|
36
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TurnUsageMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/TurnUsageMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"TurnUsageMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/TurnUsageMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,sBAAsB,GAAG;IACpC,KAAK,EAAE,EAAE,CAAC;IACV,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC;IACpB,iBAAiB,EAAE,CAAC,sBAAsB,CAAC,CAAC;IAC5C,oBAAoB,EAAE,CAAC,sBAAsB,CAAC,CAAC;CAC/C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC7B,CAAA;AAQD,MAAM,CAAC,OAAO,WAAW,gBAAgB;IACxC,EAAE,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACnH,GAAG,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACpH,IAAI,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACrH,IAAI,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACpG;AAED,qBAAa,gBAAiB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,OAAO,CAAC,OAAO,CAAS;;IAKjB,iBAAiB,CAAC,cAAc,EAAE,sBAAsB;IA4CxD,oBAAoB,CAAC,cAAc,EAAE,sBAAsB;IAelE,IAAW,OAAO,aAEjB;IAED,IAAW,eAAe,6BAEzB;IAEM,QAAQ,CAAC,MAAM,EAAE,MAAM;IAI9B,IAAW,OAAO,IAAI,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,CAUxD;IAED,IAAW,MAAM,YAEhB;IAEM,KAAK;CAMZ"}
|
|
@@ -67,6 +67,15 @@ class TurnUsageMonitor extends events_1.EventEmitter {
|
|
|
67
67
|
getUsage(turnIp) {
|
|
68
68
|
return this._turnUsage.get(turnIp);
|
|
69
69
|
}
|
|
70
|
+
get clients() {
|
|
71
|
+
const result = new Map();
|
|
72
|
+
for (const pc of this.peerConnections) {
|
|
73
|
+
if (result.has(pc.clientId))
|
|
74
|
+
continue;
|
|
75
|
+
result.set(pc.clientId, pc.client);
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
70
79
|
get closed() {
|
|
71
80
|
return this._closed;
|
|
72
81
|
}
|
package/package.json
CHANGED
package/src/ObservedClient.ts
CHANGED
|
@@ -12,6 +12,14 @@ import { ObservedSfu } from './ObservedSfu';
|
|
|
12
12
|
|
|
13
13
|
const logger = createLogger('ObservedClient');
|
|
14
14
|
|
|
15
|
+
export interface ClientIssue {
|
|
16
|
+
severity: 'critical' | 'major' | 'minor';
|
|
17
|
+
timestamp: number;
|
|
18
|
+
description?: string;
|
|
19
|
+
peerConnectionId?: string,
|
|
20
|
+
trackId?: string,
|
|
21
|
+
}
|
|
22
|
+
|
|
15
23
|
export type ObservedClientModel= {
|
|
16
24
|
clientId: string;
|
|
17
25
|
mediaUnitId: string;
|
|
@@ -46,6 +54,7 @@ export type ObservedClientEvents = {
|
|
|
46
54
|
localCandidate: IceLocalCandidate,
|
|
47
55
|
remoteCandidate: IceRemoteCandidate,
|
|
48
56
|
}],
|
|
57
|
+
issue: [ClientIssue],
|
|
49
58
|
usingturn: [boolean],
|
|
50
59
|
usermediaerror: [string],
|
|
51
60
|
};
|
|
@@ -393,6 +402,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
393
402
|
this._left = timestamp;
|
|
394
403
|
break;
|
|
395
404
|
}
|
|
405
|
+
case CallEventType.CLIENT_ISSUE: {
|
|
406
|
+
const severity = callEvent.value ? callEvent.value as ClientIssue['severity'] : 'minor';
|
|
407
|
+
|
|
408
|
+
this.emit('issue', {
|
|
409
|
+
severity,
|
|
410
|
+
timestamp: timestamp ?? Date.now(),
|
|
411
|
+
description: callEvent.message,
|
|
412
|
+
peerConnectionId: callEvent.peerConnectionId,
|
|
413
|
+
trackId: callEvent.mediaTrackId,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
396
416
|
}
|
|
397
417
|
this.reports.addCallEventReport({
|
|
398
418
|
serviceId: this.serviceId,
|
|
@@ -12,6 +12,7 @@ export type ObservedOutboundTrackModel<K extends MediaKind> = {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export type ObservedOutboundTrackEvents = {
|
|
15
|
+
qualitylimitationchanged: [string];
|
|
15
16
|
update: [{
|
|
16
17
|
elapsedTimeInMs: number;
|
|
17
18
|
}],
|
|
@@ -197,6 +198,14 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
197
198
|
if (videoSample?.framesSent && lastVideoStats?.framesSent && lastVideoStats.framesSent < videoSample.framesSent) {
|
|
198
199
|
deltaSentFrames = videoSample.framesSent - lastVideoStats.framesSent;
|
|
199
200
|
}
|
|
201
|
+
|
|
202
|
+
if (videoSample.qualityLimitationReason && lastVideoStats?.qualityLimitationReason !== videoSample.qualityLimitationReason) {
|
|
203
|
+
this.emit('qualitylimitationchanged', videoSample.qualityLimitationReason);
|
|
204
|
+
}
|
|
205
|
+
} else if (this.kind === 'audio') {
|
|
206
|
+
// const audioSample = sample as OutboundAudioTrack;
|
|
207
|
+
// const lastAudioStats = lastStat as OutboundAudioTrack | undefined;
|
|
208
|
+
|
|
200
209
|
}
|
|
201
210
|
const stats: ObservedOutboundTrackStats<Kind> = {
|
|
202
211
|
...sample,
|
package/src/Observer.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { PartialBy } from './common/utils';
|
|
|
6
6
|
import { createCallEndedEventReport, createCallStartedEventReport } from './common/callEventReports';
|
|
7
7
|
import { ObserverSinkContext } from './common/types';
|
|
8
8
|
import { ObservedSfu, ObservedSfuModel } from './ObservedSfu';
|
|
9
|
-
import { CallSummaryMonitor } from './monitors/CallSummaryMonitor';
|
|
9
|
+
import { CallSummaryMonitor, CallSummaryMonitorConfig } from './monitors/CallSummaryMonitor';
|
|
10
10
|
import { TurnUsageMonitor } from './monitors/TurnUsageMonitor';
|
|
11
11
|
import { ObservedClient } from './ObservedClient';
|
|
12
12
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
@@ -104,13 +104,19 @@ export class Observer extends EventEmitter {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
public createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
107
|
-
config: PartialBy<ObservedCallModel, 'serviceId'> & { appData: T, started?: number }
|
|
107
|
+
config: PartialBy<ObservedCallModel, 'serviceId'> & { appData: T, started?: number, reportCallStarted?: boolean, reportCallEnded?: boolean }
|
|
108
108
|
): ObservedCall<T> {
|
|
109
109
|
if (this._closed) {
|
|
110
110
|
throw new Error('Attempted to create a call source on a closed observer');
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
const {
|
|
113
|
+
const {
|
|
114
|
+
appData,
|
|
115
|
+
started = Date.now(),
|
|
116
|
+
reportCallEnded = true,
|
|
117
|
+
reportCallStarted = true,
|
|
118
|
+
...model
|
|
119
|
+
} = config;
|
|
114
120
|
const call = new ObservedCall({
|
|
115
121
|
...model,
|
|
116
122
|
serviceId: this.config.defaultServiceId,
|
|
@@ -121,7 +127,7 @@ export class Observer extends EventEmitter {
|
|
|
121
127
|
|
|
122
128
|
call.once('close', () => {
|
|
123
129
|
this._observedCalls.delete(call.callId);
|
|
124
|
-
this.reports.addCallEventReport(createCallEndedEventReport(
|
|
130
|
+
reportCallEnded && this.reports.addCallEventReport(createCallEndedEventReport(
|
|
125
131
|
call.serviceId,
|
|
126
132
|
call.roomId,
|
|
127
133
|
call.callId,
|
|
@@ -130,7 +136,7 @@ export class Observer extends EventEmitter {
|
|
|
130
136
|
});
|
|
131
137
|
|
|
132
138
|
this._observedCalls.set(call.callId, call);
|
|
133
|
-
this.reports.addCallEventReport(createCallStartedEventReport(
|
|
139
|
+
reportCallStarted && this.reports.addCallEventReport(createCallStartedEventReport(
|
|
134
140
|
call.serviceId,
|
|
135
141
|
call.roomId,
|
|
136
142
|
call.callId,
|
|
@@ -165,14 +171,14 @@ export class Observer extends EventEmitter {
|
|
|
165
171
|
return sfu;
|
|
166
172
|
}
|
|
167
173
|
|
|
168
|
-
public createCallSummaryMonitor(options?: { timeoutAfterCallClose?: number }): CallSummaryMonitor {
|
|
174
|
+
public createCallSummaryMonitor(options?: CallSummaryMonitorConfig & { timeoutAfterCallClose?: number }): CallSummaryMonitor {
|
|
169
175
|
if (this._closed) throw new Error('Cannot create a call summary monitor on a closed observer');
|
|
170
176
|
|
|
171
177
|
const existingMonitor = this._monitors.get(CallSummaryMonitor.name);
|
|
172
178
|
|
|
173
179
|
if (existingMonitor) return existingMonitor as CallSummaryMonitor;
|
|
174
180
|
|
|
175
|
-
const monitor = new CallSummaryMonitor();
|
|
181
|
+
const monitor = new CallSummaryMonitor(options);
|
|
176
182
|
const onNewCall = (call: ObservedCall) => {
|
|
177
183
|
monitor.addCall(call);
|
|
178
184
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// eslint-disable-next-line no-shadow
|
|
2
|
-
|
|
3
2
|
export enum CallEventType {
|
|
4
3
|
CALL_STARTED = 'CALL_STARTED',
|
|
5
4
|
CALL_ENDED = 'CALL_ENDED',
|
|
@@ -20,4 +19,5 @@ export enum CallEventType {
|
|
|
20
19
|
DATA_CHANNEL_ERROR = 'DATA_CHANNEL_ERROR',
|
|
21
20
|
NEGOTIATION_NEEDED = 'NEGOTIATION_NEEDED',
|
|
22
21
|
SIGNALING_STATE_CHANGE = 'SIGNALING_STATE_CHANGE',
|
|
22
|
+
CLIENT_ISSUE = 'CLIENT_ISSUE',
|
|
23
23
|
}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { ClientIssue } from '../ObservedClient';
|
|
2
|
+
|
|
1
3
|
export interface ClientSummary {
|
|
2
4
|
clientId: string;
|
|
3
5
|
mediaUnitId: string;
|
|
4
6
|
userId?: string;
|
|
5
7
|
joined: number;
|
|
8
|
+
left?: number;
|
|
6
9
|
durationInMs: number;
|
|
7
10
|
avgOutboundAudioBitrate: number,
|
|
8
11
|
avgOutboundVideoBitrate: number,
|
|
9
12
|
avgInboundAudioBitrate: number,
|
|
10
13
|
avgInboundVideoBitrate: number,
|
|
11
14
|
ewmaRttInMs: number,
|
|
15
|
+
usedTurn: boolean;
|
|
16
|
+
issues: ClientIssue[];
|
|
12
17
|
}
|
|
13
18
|
|
|
14
19
|
export interface CallSummary {
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
|
-
import { CallSummary } from './CallSummary';
|
|
2
|
+
import { CallSummary, ClientSummary } from './CallSummary';
|
|
3
3
|
import { ObservedCall } from '../ObservedCall';
|
|
4
|
-
import { ObservedClient } from '../ObservedClient';
|
|
4
|
+
import { ClientIssue, ObservedClient } from '../ObservedClient';
|
|
5
|
+
import { ObservedOutboundTrack } from '../ObservedOutboundTrack';
|
|
6
|
+
import { ObservedPeerConnection } from '../ObservedPeerConnection';
|
|
5
7
|
|
|
6
8
|
export type CallSummaryMonitorEvents = {
|
|
7
9
|
close: [],
|
|
8
10
|
summary: [CallSummary],
|
|
9
11
|
}
|
|
10
12
|
|
|
13
|
+
export type CallSummaryMonitorConfig = {
|
|
14
|
+
detectUserMediaIssues?: boolean;
|
|
15
|
+
detectMediaTrackQualityLimitationIssues?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
export declare interface CallSummaryMonitor {
|
|
12
19
|
on<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
|
|
13
20
|
off<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
|
|
@@ -19,7 +26,9 @@ export class CallSummaryMonitor extends EventEmitter {
|
|
|
19
26
|
private readonly _summaries = new Map<string, CallSummary>();
|
|
20
27
|
|
|
21
28
|
private _closed = false;
|
|
22
|
-
public constructor(
|
|
29
|
+
public constructor(
|
|
30
|
+
public readonly config: CallSummaryMonitorConfig = {},
|
|
31
|
+
) {
|
|
23
32
|
super();
|
|
24
33
|
}
|
|
25
34
|
|
|
@@ -50,7 +59,7 @@ export class CallSummaryMonitor extends EventEmitter {
|
|
|
50
59
|
|
|
51
60
|
private _addClient(callSummary: CallSummary, client: ObservedClient) {
|
|
52
61
|
if (this.closed) return;
|
|
53
|
-
const clientSummary = {
|
|
62
|
+
const clientSummary: ClientSummary = {
|
|
54
63
|
clientId: client.clientId,
|
|
55
64
|
mediaUnitId: client.mediaUnitId,
|
|
56
65
|
durationInMs: 0,
|
|
@@ -61,6 +70,8 @@ export class CallSummaryMonitor extends EventEmitter {
|
|
|
61
70
|
ewmaRttInMs: 0,
|
|
62
71
|
joined: client.created,
|
|
63
72
|
userId: client.userId,
|
|
73
|
+
usedTurn: false,
|
|
74
|
+
issues: [],
|
|
64
75
|
};
|
|
65
76
|
|
|
66
77
|
callSummary.clients.push(clientSummary);
|
|
@@ -71,7 +82,34 @@ export class CallSummaryMonitor extends EventEmitter {
|
|
|
71
82
|
}
|
|
72
83
|
};
|
|
73
84
|
|
|
85
|
+
const onUsingTurn = (usingTurn: boolean) => {
|
|
86
|
+
clientSummary.usedTurn ||= usingTurn;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const onIssue = (issue: ClientIssue) => {
|
|
90
|
+
clientSummary.issues.push(issue);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const onUserMediaError = (error: string) => {
|
|
94
|
+
if (!this.config.detectUserMediaIssues) return;
|
|
95
|
+
|
|
96
|
+
// maybe the client also sned this issue, in which case the timestamp can be more accurate
|
|
97
|
+
const alreadyDetected = clientSummary.issues.find((issue) => issue.severity === 'critical' && issue.description === error);
|
|
98
|
+
|
|
99
|
+
!alreadyDetected && clientSummary.issues.push({
|
|
100
|
+
severity: 'critical',
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
description: error,
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const onNewPeerConnection = (peerConnection: ObservedPeerConnection) => this._addPeerConnection(clientSummary, peerConnection);
|
|
107
|
+
|
|
74
108
|
client.on('update', updateClient);
|
|
109
|
+
client.on('usingturn', onUsingTurn);
|
|
110
|
+
client.on('issue', onIssue);
|
|
111
|
+
client.on('usermediaerror', onUserMediaError);
|
|
112
|
+
client.on('newpeerconnection', onNewPeerConnection);
|
|
75
113
|
client.once('close', () => {
|
|
76
114
|
const elapsedTimeInS = (Date.now() - client.created) / 1000;
|
|
77
115
|
|
|
@@ -81,7 +119,41 @@ export class CallSummaryMonitor extends EventEmitter {
|
|
|
81
119
|
clientSummary.avgOutboundVideoBitrate = (client.totalSentBytes * 8) / elapsedTimeInS;
|
|
82
120
|
clientSummary.durationInMs = elapsedTimeInS * 1000;
|
|
83
121
|
client.off('update', updateClient);
|
|
122
|
+
client.off('usingturn', onUsingTurn);
|
|
123
|
+
client.off('issue', onIssue);
|
|
124
|
+
client.off('usermediaerror', onUserMediaError);
|
|
125
|
+
client.off('newpeerconnection', onNewPeerConnection);
|
|
126
|
+
|
|
127
|
+
callSummary.durationInMs += clientSummary.durationInMs;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private _addPeerConnection(clientSummary: ClientSummary, peerConnection: ObservedPeerConnection) {
|
|
132
|
+
const onOutboundVideoTrack = (track: ObservedOutboundTrack<'video'>) => this._addOutboundVideoTrack(clientSummary, track);
|
|
133
|
+
|
|
134
|
+
peerConnection.on('newoutboundvideotrack', onOutboundVideoTrack);
|
|
135
|
+
peerConnection.once('close', () => {
|
|
136
|
+
peerConnection.off('newoutboundvideotrack', onOutboundVideoTrack);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private _addOutboundVideoTrack(clientSummary: ClientSummary, track: ObservedOutboundTrack<'video'>) {
|
|
141
|
+
const onQualityLimitationChanged = (reason: string) => {
|
|
142
|
+
if (!this.config.detectMediaTrackQualityLimitationIssues) return;
|
|
143
|
+
|
|
144
|
+
clientSummary.issues.push({
|
|
145
|
+
severity: 'minor',
|
|
146
|
+
timestamp: Date.now(),
|
|
147
|
+
description: reason,
|
|
148
|
+
peerConnectionId: track.peerConnectionId,
|
|
149
|
+
trackId: track.trackId,
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
track.once('close', () => {
|
|
154
|
+
track.off('qualitylimitationchanged', onQualityLimitationChanged);
|
|
84
155
|
});
|
|
156
|
+
track.on('qualitylimitationchanged', onQualityLimitationChanged);
|
|
85
157
|
}
|
|
86
158
|
|
|
87
159
|
public takeSummary(callId: string): CallSummary | undefined {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
import { ObservedPeerConnection } from '../ObservedPeerConnection';
|
|
3
3
|
import { ObservedICEEvents } from '../ObservedICE';
|
|
4
|
+
import { ObservedClient } from '../ObservedClient';
|
|
4
5
|
|
|
5
6
|
export type TurnUsageMonitorEvents = {
|
|
6
7
|
close: [],
|
|
@@ -111,6 +112,18 @@ export class TurnUsageMonitor extends EventEmitter {
|
|
|
111
112
|
return this._turnUsage.get(turnIp);
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
public get clients(): ReadonlyMap<string, ObservedClient> {
|
|
116
|
+
const result = new Map<string, ObservedClient>();
|
|
117
|
+
|
|
118
|
+
for (const pc of this.peerConnections) {
|
|
119
|
+
if (result.has(pc.clientId)) continue;
|
|
120
|
+
|
|
121
|
+
result.set(pc.clientId, pc.client);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
114
127
|
public get closed() {
|
|
115
128
|
return this._closed;
|
|
116
129
|
}
|