@observertc/observer-js 1.0.1-c3edea3.0 → 1.0.1-ec27289.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ObservedCall.d.ts +41 -7
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +125 -13
- package/lib/ObservedCallSummary.d.ts +18 -0
- package/lib/ObservedCallSummary.d.ts.map +1 -0
- package/lib/ObservedClient.d.ts +70 -11
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +394 -72
- package/lib/ObservedClientEventMonitor.d.ts +89 -0
- package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
- package/lib/ObservedClientEventMonitor.js +247 -0
- package/lib/ObservedClientSummary.d.ts +23 -0
- package/lib/ObservedClientSummary.d.ts.map +1 -0
- package/lib/ObservedClientSummary.js +2 -0
- package/lib/ObservedDataChannel.d.ts +6 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +30 -0
- package/lib/ObservedIceCandidatePair.d.ts +4 -0
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
- package/lib/ObservedIceCandidatePair.js +28 -0
- package/lib/ObservedIceTransport.d.ts +4 -0
- package/lib/ObservedIceTransport.d.ts.map +1 -1
- package/lib/ObservedIceTransport.js +28 -0
- package/lib/ObservedInboundTrack.d.ts +2 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +2 -0
- package/lib/ObservedOutboundTrack.d.ts +2 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +2 -0
- package/lib/ObservedPeerConnection.d.ts +14 -2
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +106 -14
- package/lib/ObservedTURN.d.ts +31 -0
- package/lib/ObservedTURN.d.ts.map +1 -0
- package/lib/ObservedTURN.js +58 -0
- package/lib/ObservedTurnServer.d.ts +25 -0
- package/lib/ObservedTurnServer.d.ts.map +1 -0
- package/lib/ObservedTurnServer.js +59 -0
- package/lib/Observer.d.ts +38 -21
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +114 -40
- package/lib/ObserverSummary.d.ts +13 -0
- package/lib/ObserverSummary.d.ts.map +1 -0
- package/lib/ObserverSummary.js +2 -0
- package/lib/common/utils.d.ts +2 -1
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +11 -3
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +7 -1
- package/lib/schema/ClientEventTypes.d.ts +100 -0
- package/lib/schema/ClientEventTypes.d.ts.map +1 -0
- package/lib/schema/ClientEventTypes.js +38 -0
- package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
- package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
- package/lib/schema/ClientMetaTypes.js +16 -0
- package/lib/updaters/CallUpdater.d.ts.map +1 -0
- package/lib/updaters/CallUpdater.js +2 -0
- package/lib/updaters/ObserverUpdater.d.ts +5 -0
- package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/ObserverUpdater.js +2 -0
- package/lib/updaters/OnAllCallObserverUpdater_.d.ts +13 -0
- package/lib/updaters/OnAllCallObserverUpdater_.d.ts.map +1 -0
- package/lib/updaters/OnAllCallObserverUpdater_.js +38 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts +13 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAllClientCallUpdater.js +37 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.d.ts +11 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.d.ts.map +1 -0
- package/lib/updaters/OnAnyCallObserverUpdater_.js +27 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts +11 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
- package/lib/updaters/OnAnyClientCallUpdater.js +27 -0
- package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
- package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
- package/lib/updaters/OnIntervalUpdater.js +17 -0
- package/lib/updaters/Updater.d.ts +6 -0
- package/lib/updaters/Updater.d.ts.map +1 -0
- package/lib/updaters/Updater.js +2 -0
- package/package.json +1 -1
- package/src/ObservedCall.ts +205 -16
- package/src/ObservedCallSummary.ts +22 -0
- package/src/ObservedClient.ts +492 -78
- package/src/ObservedClientEventMonitor.ts +301 -0
- package/src/ObservedClientSummary.ts +24 -0
- package/src/ObservedDataChannel.ts +32 -0
- package/src/ObservedIceCandidatePair.ts +26 -0
- package/src/ObservedIceTransport.ts +29 -0
- package/src/ObservedInboundTrack.ts +3 -0
- package/src/ObservedOutboundTrack.ts +3 -0
- package/src/ObservedPeerConnection.ts +120 -16
- package/src/ObservedTURN.ts +86 -0
- package/src/ObservedTurnServer.ts +72 -0
- package/src/Observer.ts +164 -64
- package/src/ObserverSummary.ts +15 -0
- package/src/common/utils.ts +12 -2
- package/src/index.ts +5 -0
- package/src/schema/ClientEventTypes.ts +112 -0
- package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
- package/src/updaters/ObserverUpdater.ts +5 -0
- package/src/updaters/OnAllCallObserverUpdater_.ts +46 -0
- package/src/updaters/OnAllClientCallUpdater.ts +46 -0
- package/src/updaters/OnAnyCallObserverUpdater_.ts +32 -0
- package/src/updaters/OnAnyClientCallUpdater.ts +32 -0
- package/src/updaters/OnIntervalUpdater.ts +19 -0
- package/src/updaters/Updater.ts +5 -0
- package/tsconfig.json +1 -1
- package/lib/schema/eventTypes.d.ts +0 -33
- package/lib/schema/eventTypes.d.ts.map +0 -1
- package/lib/schema/eventTypes.js +0 -38
- package/lib/schema/metaTypes.d.ts.map +0 -1
- package/lib/schema/metaTypes.js +0 -16
- package/lib/utils/CallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
- package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/OnAllClientCallUpdater.js +0 -58
- package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
- package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
- package/lib/utils/onAnyClientCallUpdater.js +0 -51
- package/src/schema/eventTypes.ts +0 -36
- package/src/utils/OnAllClientCallUpdater.ts +0 -68
- package/src/utils/onAnyClientCallUpdater.ts +0 -59
- /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
- /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
- /package/src/{utils → updaters}/CallUpdater.ts +0 -0
package/src/Observer.ts
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
import { createLogger } from './common/logger';
|
|
2
|
-
import { Middleware, MiddlewareProcessor } from './common/Middleware';
|
|
3
2
|
import { ObservedCall, ObservedCallSettings } from './ObservedCall';
|
|
4
3
|
import { EventEmitter } from 'events';
|
|
5
|
-
import { ClientEvent, ClientMetaData, ClientIssue, ExtensionStat } from './schema/ClientSample';
|
|
4
|
+
import { ClientEvent, ClientMetaData, ClientIssue, ExtensionStat, ClientSample } from './schema/ClientSample';
|
|
6
5
|
import { ObservedClient } from './ObservedClient';
|
|
6
|
+
import { ObservedTURN } from './ObservedTURN';
|
|
7
|
+
import { Detectors } from './detectors/Detectors';
|
|
8
|
+
import { Updater } from './updaters/Updater';
|
|
9
|
+
import { OnIntervalUpdater } from './updaters/OnIntervalUpdater';
|
|
10
|
+
import { OnAllCallObserverUpdater } from './updaters/OnAllCallObserverUpdater_';
|
|
11
|
+
import { OnAnyCallObserverUpdater } from './updaters/OnAnyCallObserverUpdater_';
|
|
7
12
|
|
|
8
13
|
const logger = createLogger('Observer');
|
|
9
14
|
|
|
10
15
|
export type ObserverEvents = {
|
|
16
|
+
'client-event': [ObservedClient, ClientEvent];
|
|
17
|
+
'call-updated': [ObservedCall],
|
|
18
|
+
'client-issue': [ObservedClient, ClientIssue],
|
|
19
|
+
'client-metadata': [ObservedClient, ClientMetaData],
|
|
20
|
+
'client-extension-stats': [ObservedClient, ExtensionStat],
|
|
11
21
|
'newcall': [ObservedCall],
|
|
22
|
+
'update': [],
|
|
12
23
|
'close': [],
|
|
13
24
|
}
|
|
14
25
|
|
|
15
|
-
export type
|
|
16
|
-
call
|
|
17
|
-
|
|
18
|
-
|
|
26
|
+
export type ObserverConfig = {
|
|
27
|
+
updatePolicy?: 'update-on-any-call-updated' | 'update-when-all-call-updated' | 'update-on-interval',
|
|
28
|
+
updateIntervalInMs?: number,
|
|
29
|
+
defaultCallUpdatePolicy?: ObservedCallSettings['updatePolicy'],
|
|
30
|
+
defaultCallUpdateIntervalInMs?: number,
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
export declare interface Observer {
|
|
@@ -26,20 +38,74 @@ export declare interface Observer {
|
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
export class Observer extends EventEmitter {
|
|
29
|
-
public readonly
|
|
30
|
-
events: new MiddlewareProcessor<ProcessorInputContext<ClientEvent>>(),
|
|
31
|
-
metaData: new MiddlewareProcessor<ProcessorInputContext<ClientMetaData>>(),
|
|
32
|
-
issues: new MiddlewareProcessor<ProcessorInputContext<ClientIssue>>(),
|
|
33
|
-
extensionStats: new MiddlewareProcessor<ProcessorInputContext<ExtensionStat>>(),
|
|
34
|
-
};
|
|
41
|
+
public readonly detectors: Detectors;
|
|
35
42
|
|
|
43
|
+
public readonly observedTURN = new ObservedTURN();
|
|
36
44
|
public readonly observedCalls = new Map<string, ObservedCall>();
|
|
45
|
+
public updater?: Updater;
|
|
46
|
+
|
|
37
47
|
public closed = false;
|
|
38
48
|
|
|
39
|
-
public
|
|
40
|
-
|
|
49
|
+
public totalAddedCall = 0;
|
|
50
|
+
public totalRemovedCall = 0;
|
|
51
|
+
public totalRttLt50Measurements = 0;
|
|
52
|
+
public totalRttLt150Measurements = 0;
|
|
53
|
+
public totalRttLt300Measurements = 0;
|
|
54
|
+
public totalRttGtOrEq300Measurements = 0;
|
|
55
|
+
public totalClientIssues = 0;
|
|
56
|
+
|
|
57
|
+
public numberOfClientsUsingTurn = 0;
|
|
58
|
+
public numberOfClients = 0;
|
|
59
|
+
public numberOfInboundRtpStreams = 0;
|
|
60
|
+
public numberOfOutboundRtpStreams = 0;
|
|
61
|
+
public numberOfDataChannels = 0;
|
|
62
|
+
public numberOfPeerConnections = 0;
|
|
63
|
+
|
|
64
|
+
public get numberOfCalls() {
|
|
65
|
+
return this.observedCalls.size;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private _timer?: ReturnType<typeof setInterval>;
|
|
69
|
+
|
|
70
|
+
public constructor(public readonly config: ObserverConfig = {
|
|
71
|
+
updatePolicy: 'update-when-all-call-updated',
|
|
72
|
+
updateIntervalInMs: undefined,
|
|
73
|
+
}) {
|
|
41
74
|
super();
|
|
42
75
|
this.setMaxListeners(Infinity);
|
|
76
|
+
this.update = this.update.bind(this);
|
|
77
|
+
|
|
78
|
+
if (this.config.updateIntervalInMs) {
|
|
79
|
+
if (this.config.updatePolicy && this.config.updatePolicy !== 'update-on-interval') {
|
|
80
|
+
throw new Error('update policy must be update-on-interval if updateIntervalInMs is set in config');
|
|
81
|
+
}
|
|
82
|
+
this._timer = setInterval(this.update.bind(this), this.config.updateIntervalInMs);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (this.config.updateIntervalInMs) {
|
|
86
|
+
if (this.config.updatePolicy !== 'update-on-interval') {
|
|
87
|
+
throw new Error('updatePolicy must be update-on-interval if updateIntervalInMs is set in config');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
switch (this.config.updatePolicy) {
|
|
91
|
+
case 'update-on-any-call-updated':
|
|
92
|
+
this.updater = new OnAllCallObserverUpdater(this);
|
|
93
|
+
break;
|
|
94
|
+
case 'update-when-all-call-updated':
|
|
95
|
+
this.updater = new OnAnyCallObserverUpdater(this);
|
|
96
|
+
break;
|
|
97
|
+
case 'update-on-interval':
|
|
98
|
+
if (!this.config.updateIntervalInMs) {
|
|
99
|
+
throw new Error('updateIntervalInMs setting in config must be set if updatePolicy is update-on-interval');
|
|
100
|
+
}
|
|
101
|
+
this.updater = new OnIntervalUpdater(
|
|
102
|
+
this.config.updateIntervalInMs,
|
|
103
|
+
this.update.bind(this),
|
|
104
|
+
);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.detectors = new Detectors();
|
|
43
109
|
}
|
|
44
110
|
|
|
45
111
|
public getObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(callId: string): ObservedCall<T> | undefined {
|
|
@@ -54,86 +120,120 @@ export class Observer extends EventEmitter {
|
|
|
54
120
|
if (this.closed) {
|
|
55
121
|
throw new Error('Attempted to create a call source on a closed observer');
|
|
56
122
|
}
|
|
123
|
+
if (!settings.updatePolicy) {
|
|
124
|
+
settings.updatePolicy = this.config.defaultCallUpdatePolicy;
|
|
125
|
+
settings.updateIntervalInMs = this.config.defaultCallUpdateIntervalInMs;
|
|
126
|
+
}
|
|
57
127
|
|
|
58
128
|
const observedCall = new ObservedCall(settings, this);
|
|
129
|
+
const onCallUpdated = () => this._onObservedCallUpdated(observedCall);
|
|
59
130
|
|
|
60
131
|
if (this.observedCalls.has(observedCall.callId)) throw new Error(`Observed Call with id ${observedCall.callId} already exists`);
|
|
61
132
|
|
|
62
133
|
observedCall.once('close', () => {
|
|
63
134
|
this.observedCalls.delete(observedCall.callId);
|
|
135
|
+
observedCall.off('update', onCallUpdated);
|
|
136
|
+
++this.totalRemovedCall;
|
|
64
137
|
});
|
|
65
138
|
|
|
66
139
|
this.observedCalls.set(observedCall.callId, observedCall);
|
|
140
|
+
observedCall.on('update', onCallUpdated);
|
|
141
|
+
++this.totalAddedCall;
|
|
67
142
|
|
|
68
143
|
this.emit('newcall', observedCall);
|
|
69
144
|
|
|
70
145
|
return observedCall;
|
|
71
146
|
}
|
|
72
147
|
|
|
73
|
-
public
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
public removeClientEventMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientEvent>>[]): Observer {
|
|
81
|
-
|
|
82
|
-
this.processors.events.removeMiddleware(...middlewares);
|
|
83
|
-
|
|
84
|
-
return this;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
public addClientMetaDataMiddleware(...middlewares: Middleware<ProcessorInputContext<ClientMetaData>>[]): Observer {
|
|
88
|
-
|
|
89
|
-
this.processors.metaData.addMiddleware(...middlewares);
|
|
148
|
+
public close() {
|
|
149
|
+
if (this.closed) {
|
|
150
|
+
return logger.debug('Attempted to close twice');
|
|
151
|
+
}
|
|
152
|
+
this.closed = true;
|
|
153
|
+
clearInterval(this._timer);
|
|
154
|
+
this._timer = undefined;
|
|
90
155
|
|
|
91
|
-
|
|
156
|
+
this.observedCalls.forEach((call) => call.close());
|
|
157
|
+
|
|
158
|
+
this.emit('close');
|
|
92
159
|
}
|
|
93
160
|
|
|
94
|
-
public
|
|
95
|
-
|
|
96
|
-
|
|
161
|
+
public accept(sample: ClientSample) {
|
|
162
|
+
if (this.closed) return;
|
|
163
|
+
if (!sample.callId) return logger.warn('Received sample without callId. %o', sample);
|
|
164
|
+
if (!sample.clientId) return logger.warn('Received sample without clientId %o', sample);
|
|
97
165
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
166
|
+
const call = this.getObservedCall(sample.callId) ?? this.createObservedCall({
|
|
167
|
+
callId: sample.callId,
|
|
168
|
+
updateIntervalInMs: this.config.defaultCallUpdateIntervalInMs,
|
|
169
|
+
updatePolicy: this.config.defaultCallUpdatePolicy,
|
|
170
|
+
});
|
|
102
171
|
|
|
103
|
-
|
|
172
|
+
const client = call.getObservedClient(sample.clientId) ?? call.createObservedClient({
|
|
173
|
+
clientId: sample.clientId,
|
|
174
|
+
});
|
|
104
175
|
|
|
105
|
-
|
|
176
|
+
client.accept(sample);
|
|
106
177
|
}
|
|
107
178
|
|
|
108
|
-
public
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return this;
|
|
113
|
-
}
|
|
179
|
+
public update() {
|
|
180
|
+
if (this.closed) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
114
183
|
|
|
115
|
-
|
|
184
|
+
this.numberOfInboundRtpStreams = 0;
|
|
185
|
+
this.numberOfOutboundRtpStreams = 0;
|
|
186
|
+
this.numberOfPeerConnections = 0;
|
|
187
|
+
this.numberOfDataChannels = 0;
|
|
188
|
+
this.numberOfClients = 0;
|
|
189
|
+
this.numberOfClientsUsingTurn = 0;
|
|
190
|
+
|
|
191
|
+
for (const call of this.observedCalls.values()) {
|
|
192
|
+
this.numberOfInboundRtpStreams += call.numberOfInboundRtpStreams;
|
|
193
|
+
this.numberOfOutboundRtpStreams += call.numberOfOutboundRtpStreams;
|
|
194
|
+
this.numberOfPeerConnections += call.numberOfPeerConnections;
|
|
195
|
+
this.numberOfDataChannels += call.numberOfDataChannels;
|
|
196
|
+
this.numberOfClients += call.numberOfClients;
|
|
197
|
+
this.numberOfClientsUsingTurn += call.clientsUsedTurn.size;
|
|
198
|
+
}
|
|
116
199
|
|
|
117
|
-
this.
|
|
200
|
+
this.observedTURN.update();
|
|
118
201
|
|
|
119
|
-
|
|
202
|
+
this.emit('update');
|
|
120
203
|
}
|
|
121
204
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.
|
|
125
|
-
|
|
126
|
-
|
|
205
|
+
private _onObservedCallUpdated(call: ObservedCall) {
|
|
206
|
+
this.totalRttLt50Measurements += call.deltaRttLt50Measurements;
|
|
207
|
+
this.totalRttLt150Measurements += call.deltaRttLt150Measurements;
|
|
208
|
+
this.totalRttLt300Measurements += call.deltaRttLt300Measurements;
|
|
209
|
+
this.totalRttGtOrEq300Measurements += call.deltaRttGtOrEq300Measurements;
|
|
210
|
+
this.totalClientIssues += call.deltaNumberOfIssues;
|
|
127
211
|
}
|
|
128
212
|
|
|
129
|
-
public
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
213
|
+
// public resetSummaryMetrics() {
|
|
214
|
+
// this.totalAddedCall = 0;
|
|
215
|
+
// this.totalRemovedCall = 0;
|
|
216
|
+
// this.totalRttLt50Measurements = 0;
|
|
217
|
+
// this.totalRttLt150Measurements = 0;
|
|
218
|
+
// this.totalRttLt300Measurements = 0;
|
|
219
|
+
// this.totalRttGtOrEq300Measurements = 0;
|
|
220
|
+
// this.totalClientIssues = 0;
|
|
221
|
+
// }
|
|
222
|
+
|
|
223
|
+
// public createSummary(): ObserverSummary {
|
|
224
|
+
// return {
|
|
225
|
+
// totalAddedCall: this.totalAddedCall,
|
|
226
|
+
// totalRemovedCall: this.totalRemovedCall,
|
|
227
|
+
// totalRttLt50Measurements: this.totalRttLt50Measurements,
|
|
228
|
+
// totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
229
|
+
// totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
230
|
+
// totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
231
|
+
|
|
232
|
+
// totalClientIssues: this.totalClientIssues,
|
|
233
|
+
// currentActiveCalls: this.observedCalls.size,
|
|
234
|
+
// currentNumberOfClients: this.numberOfClients,
|
|
235
|
+
// currentNumberOfClientsUsingTURN: this.numberOfClientsUsedTurn,
|
|
236
|
+
// };
|
|
237
|
+
// }
|
|
134
238
|
|
|
135
|
-
this.observedCalls.forEach((call) => call.close());
|
|
136
|
-
|
|
137
|
-
this.emit('close');
|
|
138
|
-
}
|
|
139
239
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ObserverSummary = {
|
|
2
|
+
currentActiveCalls: number;
|
|
3
|
+
currentNumberOfClientsUsingTURN: number;
|
|
4
|
+
currentNumberOfClients: number;
|
|
5
|
+
|
|
6
|
+
totalAddedCall: number;
|
|
7
|
+
totalRemovedCall: number;
|
|
8
|
+
|
|
9
|
+
totalRttLt50Measurements: number,
|
|
10
|
+
totalRttLt150Measurements: number,
|
|
11
|
+
totalRttLt300Measurements: number,
|
|
12
|
+
totalRttGtOrEq300Measurements: number,
|
|
13
|
+
|
|
14
|
+
totalClientIssues: number,
|
|
15
|
+
}
|
package/src/common/utils.ts
CHANGED
|
@@ -30,9 +30,19 @@ export function isValidUuid(str: string): boolean {
|
|
|
30
30
|
return regexp.test(str);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export function
|
|
33
|
+
export function getAverage(arr: number[], defaultAvgIfArrLengthIs0 = 0): number {
|
|
34
|
+
if (arr.length === 0) return defaultAvgIfArrLengthIs0;
|
|
35
|
+
|
|
36
|
+
return arr.reduce((a, b) => a + b, 0) / arr.length;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function getMedian(arr: number[], copyArrayForSorting = true): number {
|
|
34
40
|
// Sort the array in ascending order
|
|
35
|
-
const sortedArr =
|
|
41
|
+
const sortedArr = copyArrayForSorting
|
|
42
|
+
? arr.slice().sort((a, b) => a - b)
|
|
43
|
+
: arr.sort((a, b) => a-b)
|
|
44
|
+
|
|
45
|
+
;
|
|
36
46
|
|
|
37
47
|
// Calculate the middle index
|
|
38
48
|
const mid = Math.floor(sortedArr.length / 2);
|
package/src/index.ts
CHANGED
|
@@ -19,5 +19,10 @@ export { ObservedIceCandidatePair } from './ObservedIceCandidatePair';
|
|
|
19
19
|
export { ObservedIceCandidate } from './ObservedIceCandidate';
|
|
20
20
|
export { ObservedIceTransport } from './ObservedIceTransport';
|
|
21
21
|
export { ObservedPeerConnectionTransport } from './ObservedPeerConnectionTransport';
|
|
22
|
+
export { ClientEventTypes } from './schema/ClientEventTypes';
|
|
23
|
+
export { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
24
|
+
export { ClientSample } from './schema/ClientSample';
|
|
25
|
+
export { ScoreCalculator } from './scores/ScoreCalculator';
|
|
26
|
+
export { ObservedClientEventMonitor } from './ObservedClientEventMonitor';
|
|
22
27
|
|
|
23
28
|
export { Middleware } from './common/Middleware';
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/* eslint-disable no-shadow */
|
|
2
|
+
|
|
3
|
+
export enum ClientEventTypes {
|
|
4
|
+
CLIENT_JOINED = 'CLIENT_JOINED',
|
|
5
|
+
CLIENT_LEFT = 'CLIENT_LEFT',
|
|
6
|
+
PEER_CONNECTION_OPENED = 'PEER_CONNECTION_OPENED',
|
|
7
|
+
PEER_CONNECTION_CLOSED = 'PEER_CONNECTION_CLOSED',
|
|
8
|
+
MEDIA_TRACK_ADDED = 'MEDIA_TRACK_ADDED',
|
|
9
|
+
MEDIA_TRACK_REMOVED = 'MEDIA_TRACK_REMOVED',
|
|
10
|
+
MEDIA_TRACK_RESUMED = 'MEDIA_TRACK_RESUMED',
|
|
11
|
+
MEDIA_TRACK_MUTED = 'MEDIA_TRACK_MUTED',
|
|
12
|
+
MEDIA_TRACK_UNMUTED = 'MEDIA_TRACK_UNMUTED',
|
|
13
|
+
ICE_GATHERING_STATE_CHANGED = 'ICE_GATHERING_STATE_CHANGED',
|
|
14
|
+
PEER_CONNECTION_STATE_CHANGED = 'PEER_CONNECTION_STATE_CHANGED',
|
|
15
|
+
ICE_CONNECTION_STATE_CHANGED = 'ICE_CONNECTION_STATE_CHANGED',
|
|
16
|
+
DATA_CHANNEL_OPEN = 'DATA_CHANNEL_OPEN',
|
|
17
|
+
DATA_CHANNEL_CLOSED = 'DATA_CHANNEL_CLOSED',
|
|
18
|
+
DATA_CHANNEL_ERROR = 'DATA_CHANNEL_ERROR',
|
|
19
|
+
NEGOTIATION_NEEDED = 'NEGOTIATION_NEEDED',
|
|
20
|
+
SIGNALING_STATE_CHANGE = 'SIGNALING_STATE_CHANGE',
|
|
21
|
+
ICE_GATHERING_STATE_CHANGE = 'ICE_GATHERING_STATE_CHANGE',
|
|
22
|
+
ICE_CONNECTION_STATE_CHANGE = 'ICE_CONNECTION_STATE_CHANGE',
|
|
23
|
+
ICE_CANDIDATE = 'ICE_CANDIDATE',
|
|
24
|
+
|
|
25
|
+
// mediasoup events
|
|
26
|
+
PRODUCER_ADDED = 'PRODUCER_ADDED',
|
|
27
|
+
PRODUCER_REMOVED = 'PRODUCER_REMOVED',
|
|
28
|
+
PRODUCER_PAUSED = 'PRODUCER_PAUSED',
|
|
29
|
+
PRODUCER_RESUMED = 'PRODUCER_RESUMED',
|
|
30
|
+
CONSUMER_ADDED = 'CONSUMER_ADDED',
|
|
31
|
+
CONSUMER_REMOVED = 'CONSUMER_REMOVED',
|
|
32
|
+
DATA_PRODUCER_CREATED = 'DATA_PRODUCER_CREATED',
|
|
33
|
+
DATA_PRODUCER_CLOSED = 'DATA_PRODUCER_CLOSED',
|
|
34
|
+
DATA_CONSUMER_CREATED = 'DATA_CONSUMER_CREATED',
|
|
35
|
+
DATA_CONSUMER_CLOSED = 'DATA_CONSUMER_CLOSED',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PeerConnectionOpenedEventPayload extends Record<string, unknown> {
|
|
39
|
+
peerConnectionId: string;
|
|
40
|
+
iceConnectionState: string;
|
|
41
|
+
iceGatheringState: string;
|
|
42
|
+
signalingState: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface PeerConnectionClosedEventPayload extends Record<string, unknown> {
|
|
46
|
+
peerConnectionId: string;
|
|
47
|
+
iceConnectionState: string;
|
|
48
|
+
iceGatheringState: string;
|
|
49
|
+
signalingState: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface MediaTrackMutedEventPayload extends Record<string, unknown> {
|
|
53
|
+
trackId: string;
|
|
54
|
+
kind: 'audio' | 'video';
|
|
55
|
+
label?: string;
|
|
56
|
+
muted: boolean;
|
|
57
|
+
enabled: boolean;
|
|
58
|
+
readyState: string;
|
|
59
|
+
contentHint?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface MediaTrackUnmutedEventPayload extends Record<string, unknown> {
|
|
63
|
+
trackId: string;
|
|
64
|
+
kind: 'audio' | 'video';
|
|
65
|
+
label?: string;
|
|
66
|
+
muted: boolean;
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
readyState: string;
|
|
69
|
+
contentHint?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface MediaTrackAddedEventPayload extends Record<string, unknown> {
|
|
73
|
+
trackId: string;
|
|
74
|
+
kind: 'audio' | 'video';
|
|
75
|
+
label?: string;
|
|
76
|
+
muted: boolean;
|
|
77
|
+
enabled: boolean;
|
|
78
|
+
readyState: string;
|
|
79
|
+
contentHint?: string;
|
|
80
|
+
constraints: MediaTrackConstraints,
|
|
81
|
+
capabilities: MediaTrackCapabilities,
|
|
82
|
+
settings: MediaTrackSettings,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface MediaTrackRemovedEventPayload extends Record<string, unknown> {
|
|
86
|
+
trackId: string;
|
|
87
|
+
kind: 'audio' | 'video';
|
|
88
|
+
label?: string;
|
|
89
|
+
muted: boolean;
|
|
90
|
+
enabled: boolean;
|
|
91
|
+
readyState: string;
|
|
92
|
+
contentHint?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface DataChannelErrorEventPayload extends Record<string, unknown> {
|
|
96
|
+
label: string;
|
|
97
|
+
readyState: string;
|
|
98
|
+
dataChannelId: string,
|
|
99
|
+
error: string,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface DataChannelOpenEventPayload extends Record<string, unknown> {
|
|
103
|
+
label: string;
|
|
104
|
+
readyState: string;
|
|
105
|
+
dataChannelId: string,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface DataChannelClosedEventPayload extends Record<string, unknown> {
|
|
109
|
+
label: string;
|
|
110
|
+
readyState: string;
|
|
111
|
+
dataChannelId: string,
|
|
112
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ObservedCall } from '../ObservedCall';
|
|
2
|
+
import { Observer } from '../Observer';
|
|
3
|
+
import { Updater } from './Updater';
|
|
4
|
+
|
|
5
|
+
export class OnAllCallObserverUpdater implements Updater {
|
|
6
|
+
public readonly name = 'OnAllCallObserverUpdater';
|
|
7
|
+
public readonly description = 'Call Observer\'s update() method when all of the ObservedCalls are updated';
|
|
8
|
+
|
|
9
|
+
private readonly _updatedCalls = new Set<string>();
|
|
10
|
+
|
|
11
|
+
public constructor(
|
|
12
|
+
private observer: Observer
|
|
13
|
+
) {
|
|
14
|
+
this._onNewObservedCall = this._onNewObservedCall.bind(this);
|
|
15
|
+
|
|
16
|
+
this.observer.once('close', () => {
|
|
17
|
+
this.observer.off('newcall', this._onNewObservedCall);
|
|
18
|
+
});
|
|
19
|
+
this.observer.on('newcall', this._onNewObservedCall);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
close(): void {
|
|
23
|
+
// do nothing, because we unsubscribe once close is emitted from observer
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private _onNewObservedCall(observedCall: ObservedCall) {
|
|
27
|
+
const onUpdate = () => this._onObservedCallUpdated(observedCall);
|
|
28
|
+
|
|
29
|
+
observedCall.once('close', () => {
|
|
30
|
+
observedCall.off('update', onUpdate);
|
|
31
|
+
this._updatedCalls.delete(observedCall.callId);
|
|
32
|
+
});
|
|
33
|
+
observedCall.on('update', onUpdate);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private _onObservedCallUpdated(observedCall: ObservedCall) {
|
|
37
|
+
if (observedCall.closed) return;
|
|
38
|
+
|
|
39
|
+
this._updatedCalls.add(observedCall.callId);
|
|
40
|
+
|
|
41
|
+
if (this._updatedCalls.size < this.observer.observedCalls.size) return;
|
|
42
|
+
|
|
43
|
+
this._updatedCalls.clear();
|
|
44
|
+
this.observer.update();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ObservedCall } from '../ObservedCall';
|
|
2
|
+
import { ObservedClient } from '../ObservedClient';
|
|
3
|
+
import { Updater } from './Updater';
|
|
4
|
+
|
|
5
|
+
export class OnAllClientCallUpdater implements Updater {
|
|
6
|
+
readonly name = 'OnAllClientCallUpdater';
|
|
7
|
+
readonly description = 'Call the update() method of the ObservedCall once all client has been updated';
|
|
8
|
+
|
|
9
|
+
private readonly _updatedClients = new Set<string>();
|
|
10
|
+
|
|
11
|
+
public constructor(
|
|
12
|
+
private _observedCall: ObservedCall
|
|
13
|
+
) {
|
|
14
|
+
this._onNewObservedClient = this._onNewObservedClient.bind(this);
|
|
15
|
+
|
|
16
|
+
this._observedCall.once('close', () => {
|
|
17
|
+
this._observedCall.off('newclient', this._onNewObservedClient);
|
|
18
|
+
});
|
|
19
|
+
this._observedCall.on('newclient', this._onNewObservedClient);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public close(): void {
|
|
23
|
+
// do nothing, as close once emitted unsubscription happened
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private _onNewObservedClient(observedClient: ObservedClient) {
|
|
27
|
+
const onUpdate = () => this._onClientUpdate(observedClient);
|
|
28
|
+
|
|
29
|
+
observedClient.once('close', () => {
|
|
30
|
+
observedClient.off('update', onUpdate);
|
|
31
|
+
this._updatedClients.delete(observedClient.clientId);
|
|
32
|
+
});
|
|
33
|
+
observedClient.on('update', onUpdate);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private _onClientUpdate(observedClient: ObservedClient) {
|
|
37
|
+
this._updatedClients.add(observedClient.clientId);
|
|
38
|
+
|
|
39
|
+
if (this._updatedClients.size < this._observedCall.observedClients.size) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this._updatedClients.clear();
|
|
43
|
+
this._observedCall.update();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ObservedCall } from '../ObservedCall';
|
|
2
|
+
import { Observer } from '../Observer';
|
|
3
|
+
import { Updater } from './Updater';
|
|
4
|
+
|
|
5
|
+
export class OnAnyCallObserverUpdater implements Updater {
|
|
6
|
+
public readonly name = 'OnAnyCallObserverUpdater';
|
|
7
|
+
public readonly description = 'Call Observer\'s update() method on any of the ObservedCall is updated';
|
|
8
|
+
|
|
9
|
+
public constructor(
|
|
10
|
+
private observver: Observer
|
|
11
|
+
) {
|
|
12
|
+
this._onNewObservedCall = this._onNewObservedCall.bind(this);
|
|
13
|
+
|
|
14
|
+
this.observver.once('close', () => {
|
|
15
|
+
this.observver.off('newcall', this._onNewObservedCall);
|
|
16
|
+
});
|
|
17
|
+
this.observver.on('newcall', this._onNewObservedCall);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
close(): void {
|
|
21
|
+
// do nothing, because we unsubscribe once close is emitted from observer
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private _onNewObservedCall(observedCall: ObservedCall) {
|
|
25
|
+
const onUpdate = () => this.observver.update();
|
|
26
|
+
|
|
27
|
+
observedCall.once('close', () => {
|
|
28
|
+
observedCall.off('update', onUpdate);
|
|
29
|
+
});
|
|
30
|
+
observedCall.on('update', onUpdate);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ObservedCall } from '../ObservedCall';
|
|
2
|
+
import { ObservedClient } from '../ObservedClient';
|
|
3
|
+
import { Updater } from './Updater';
|
|
4
|
+
|
|
5
|
+
export class OnAnyClientCallUpdater implements Updater {
|
|
6
|
+
readonly name = 'OnAnyClientCallUpdater';
|
|
7
|
+
readonly description = 'Call the update() method of the ObservedCall when any of the client has been updated';
|
|
8
|
+
|
|
9
|
+
public constructor(
|
|
10
|
+
private _observedCall: ObservedCall
|
|
11
|
+
) {
|
|
12
|
+
this._onNewObservedClient = this._onNewObservedClient.bind(this);
|
|
13
|
+
|
|
14
|
+
this._observedCall.once('close', () => {
|
|
15
|
+
this._observedCall.off('newclient', this._onNewObservedClient);
|
|
16
|
+
});
|
|
17
|
+
this._observedCall.on('newclient', this._onNewObservedClient);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public close(): void {
|
|
21
|
+
// do nothing, as close once emitted unsubscription happened
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private _onNewObservedClient(observedClient: ObservedClient) {
|
|
25
|
+
const onUpdate = () => this._observedCall.update();
|
|
26
|
+
|
|
27
|
+
observedClient.once('close', () => {
|
|
28
|
+
observedClient.off('update', onUpdate);
|
|
29
|
+
});
|
|
30
|
+
observedClient.on('update', onUpdate);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Updater } from './Updater';
|
|
2
|
+
|
|
3
|
+
export class OnIntervalUpdater implements Updater {
|
|
4
|
+
readonly name = 'OnIntervalUpdater';
|
|
5
|
+
readonly description = 'Call the update() method given in the constructor once the interval elapsed';
|
|
6
|
+
|
|
7
|
+
public timer: ReturnType<typeof setInterval>;
|
|
8
|
+
|
|
9
|
+
public constructor(
|
|
10
|
+
intervalInMs: number,
|
|
11
|
+
private readonly _update: () => void,
|
|
12
|
+
) {
|
|
13
|
+
this.timer = setInterval(() => this._update(), intervalInMs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public close(): void {
|
|
17
|
+
clearInterval(this.timer);
|
|
18
|
+
}
|
|
19
|
+
}
|