@observertc/observer-js 1.0.1-72a904d.0 → 1.0.1-9341fcd.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 +4 -8
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +16 -72
- package/lib/ObservedCallEventMonitor.d.ts +104 -0
- package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
- package/lib/ObservedCallEventMonitor.js +314 -0
- package/lib/ObservedClient.d.ts +16 -8
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +257 -99
- package/lib/ObservedClientEventMonitor.d.ts +89 -0
- package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
- package/lib/ObservedClientEventMonitor.js +247 -0
- package/lib/ObservedDataChannel.d.ts +2 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +2 -0
- package/lib/ObservedIceCandidatePair.d.ts +2 -1
- package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
- package/lib/ObservedIceCandidatePair.js +17 -1
- 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.map +1 -1
- package/lib/ObservedPeerConnection.js +22 -6
- package/lib/Observer.d.ts +9 -7
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +16 -22
- package/lib/ObserverEventMonitor.d.ts +106 -0
- package/lib/ObserverEventMonitor.d.ts.map +1 -0
- package/lib/ObserverEventMonitor.js +320 -0
- package/lib/ObserverSummary.d.ts +2 -0
- package/lib/ObserverSummary.d.ts.map +1 -1
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.d.ts.map +1 -1
- package/lib/common/utils.js +7 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +5 -1
- package/lib/schema/ClientEventTypes.d.ts +60 -0
- package/lib/schema/ClientEventTypes.d.ts.map +1 -1
- package/lib/schema/ClientSample.d.ts +1 -1
- package/lib/schema/ClientSample.d.ts.map +1 -1
- package/lib/updaters/{OnAllCallObserverUpdater_.d.ts → OnAllCallObserverUpdater.d.ts} +3 -1
- package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/{OnAllCallObserverUpdater_.js → OnAllCallObserverUpdater.js} +13 -1
- package/lib/updaters/OnAllClientCallUpdater.d.ts +2 -0
- package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -1
- package/lib/updaters/OnAllClientCallUpdater.js +16 -0
- package/lib/updaters/{OnAnyCallObserverUpdater_.d.ts → OnAnyCallObserverUpdater.d.ts} +2 -1
- package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
- package/lib/updaters/{OnAnyCallObserverUpdater_.js → OnAnyCallObserverUpdater.js} +11 -1
- package/lib/updaters/OnAnyClientCallUpdater.d.ts +1 -0
- package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -1
- package/lib/updaters/OnAnyClientCallUpdater.js +11 -2
- package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
- package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
- package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
- package/package.json +1 -1
- package/src/ObservedCall.ts +56 -82
- package/src/ObservedCallEventMonitor.ts +392 -0
- package/src/ObservedClient.ts +335 -114
- package/src/ObservedClientEventMonitor.ts +301 -0
- package/src/ObservedDataChannel.ts +3 -0
- package/src/ObservedIceCandidatePair.ts +18 -2
- package/src/ObservedInboundTrack.ts +3 -0
- package/src/ObservedOutboundTrack.ts +3 -0
- package/src/ObservedPeerConnection.ts +25 -10
- package/src/Observer.ts +47 -29
- package/src/ObserverEventMonitor.ts +398 -0
- package/src/ObserverSummary.ts +3 -1
- package/src/common/utils.ts +6 -0
- package/src/index.ts +2 -0
- package/src/schema/ClientEventTypes.ts +64 -0
- package/src/schema/ClientSample.ts +1 -1
- package/src/updaters/{OnAllCallObserverUpdater_.ts → OnAllCallObserverUpdater.ts} +14 -1
- package/src/updaters/OnAllClientCallUpdater.ts +15 -0
- package/src/updaters/{OnAnyCallObserverUpdater_.ts → OnAnyCallObserverUpdater.ts} +11 -2
- package/src/updaters/OnAnyClientCallUpdater.ts +9 -2
- package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
- package/lib/updaters/OnAllCallObserverUpdater_.d.ts.map +0 -1
- package/lib/updaters/OnAnyCallObserverUpdater_.d.ts.map +0 -1
package/src/ObservedClient.ts
CHANGED
|
@@ -7,10 +7,9 @@ import * as MetaData from './schema/ClientMetaTypes';
|
|
|
7
7
|
import { ClientEventTypes } from './schema/ClientEventTypes';
|
|
8
8
|
import { ObservedCall } from './ObservedCall';
|
|
9
9
|
import { ClientMetaTypes } from './schema/ClientMetaTypes';
|
|
10
|
-
import {
|
|
10
|
+
import { parseJsonAs } from './common/utils';
|
|
11
11
|
import { CalculatedScore } from './scores/CalculatedScore';
|
|
12
12
|
import { Detectors } from './detectors/Detectors';
|
|
13
|
-
import { ObservedClientSummary } from './ObservedClientSummary';
|
|
14
13
|
|
|
15
14
|
const logger = createLogger('ObservedClient');
|
|
16
15
|
|
|
@@ -34,8 +33,9 @@ export type ObservedClientEvents = {
|
|
|
34
33
|
left: [];
|
|
35
34
|
usingturn: [boolean];
|
|
36
35
|
usermediaerror: [string];
|
|
36
|
+
extensionStats: [ExtensionStat];
|
|
37
|
+
clientEvent: [ClientEvent];
|
|
37
38
|
|
|
38
|
-
// do we need this?
|
|
39
39
|
newpeerconnection: [ObservedPeerConnection];
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -65,6 +65,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
65
65
|
|
|
66
66
|
public joinedAt?: number;
|
|
67
67
|
public leftAt?: number;
|
|
68
|
+
public closedAt?: number;
|
|
68
69
|
// the timestamp of the CLIENT_JOINED event
|
|
69
70
|
public operationSystem?: MetaData.OperationSystem;
|
|
70
71
|
public engine?: MetaData.Engine;
|
|
@@ -73,8 +74,10 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
73
74
|
public mediaConstraints: string[] = [];
|
|
74
75
|
|
|
75
76
|
public usingTURN = false;
|
|
77
|
+
public usingTCP = false;
|
|
76
78
|
public availableOutgoingBitrate = 0;
|
|
77
79
|
public availableIncomingBitrate = 0;
|
|
80
|
+
|
|
78
81
|
public totalInboundPacketsLost = 0;
|
|
79
82
|
public totalInboundPacketsReceived = 0;
|
|
80
83
|
public totalOutboundPacketsSent = 0;
|
|
@@ -100,7 +103,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
100
103
|
public deltaInboundPacketsLost = 0;
|
|
101
104
|
public deltaInboundPacketsReceived = 0;
|
|
102
105
|
public deltaOutboundPacketsSent = 0;
|
|
103
|
-
public deltaRttInMsMeasurements: number[] = [];
|
|
104
106
|
public deltaTransportSentBytes = 0;
|
|
105
107
|
public deltaTransportReceivedBytes = 0;
|
|
106
108
|
public deltaRttLt50Measurements = 0;
|
|
@@ -108,7 +110,10 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
108
110
|
public deltaRttLt300Measurements = 0;
|
|
109
111
|
public deltaRttGtOrEq300Measurements = 0;
|
|
110
112
|
|
|
111
|
-
public
|
|
113
|
+
public currentMaxRttInMs?: number;
|
|
114
|
+
public currentMinRttInMs?: number;
|
|
115
|
+
public currentAvgRttInMs?: number;
|
|
116
|
+
|
|
112
117
|
public sendingAudioBitrate = 0;
|
|
113
118
|
public sendingVideoBitrate = 0;
|
|
114
119
|
public receivingAudioBitrate = 0;
|
|
@@ -128,11 +133,13 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
128
133
|
|
|
129
134
|
public totalScoreSum = 0;
|
|
130
135
|
public numberOfScoreMeasurements = 0;
|
|
131
|
-
public
|
|
136
|
+
public totalNumberOfIssues = 0;
|
|
132
137
|
|
|
133
138
|
public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
|
|
134
139
|
public issues: ClientIssue[] = [];
|
|
135
140
|
|
|
141
|
+
private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
|
|
142
|
+
|
|
136
143
|
public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
|
|
137
144
|
super();
|
|
138
145
|
this.setMaxListeners(Infinity);
|
|
@@ -157,6 +164,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
157
164
|
|
|
158
165
|
Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
159
166
|
|
|
167
|
+
this.closedAt = Date.now();
|
|
168
|
+
|
|
160
169
|
this.emit('close');
|
|
161
170
|
}
|
|
162
171
|
|
|
@@ -166,7 +175,9 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
166
175
|
const now = Date.now();
|
|
167
176
|
const elapsedInMs = now - this.updated;
|
|
168
177
|
const elapsedInSeconds = elapsedInMs / 1000;
|
|
169
|
-
|
|
178
|
+
let sumOfRtts = 0;
|
|
179
|
+
let numberOfRttMeasurements = 0;
|
|
180
|
+
|
|
170
181
|
++this.acceptedSamples;
|
|
171
182
|
|
|
172
183
|
this.availableIncomingBitrate = 0;
|
|
@@ -184,7 +195,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
184
195
|
this.deltaSentVideoBytes = 0;
|
|
185
196
|
this.deltaTransportReceivedBytes = 0;
|
|
186
197
|
this.deltaTransportSentBytes = 0;
|
|
187
|
-
this.deltaRttInMsMeasurements = [];
|
|
188
198
|
this.deltaRttLt50Measurements = 0;
|
|
189
199
|
this.deltaRttLt150Measurements = 0;
|
|
190
200
|
this.deltaRttLt300Measurements = 0;
|
|
@@ -196,14 +206,95 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
196
206
|
this.numberOfInbundTracks = 0;
|
|
197
207
|
this.numberOfOutboundRtpStreams = 0;
|
|
198
208
|
this.numberOfOutboundTracks = 0;
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
this.usingTURN = false;
|
|
210
|
+
this.usingTCP = false;
|
|
211
|
+
this.currentMinRttInMs = undefined;
|
|
212
|
+
this.currentMaxRttInMs = undefined;
|
|
213
|
+
|
|
214
|
+
this._mergeInjections(sample);
|
|
205
215
|
|
|
206
|
-
|
|
216
|
+
const clientEventsPostBuffer: ClientEvent[] = [];
|
|
217
|
+
|
|
218
|
+
for (const clientEvent of sample.clientEvents ?? []) {
|
|
219
|
+
this._processClientEvent(clientEvent, clientEventsPostBuffer);
|
|
220
|
+
|
|
221
|
+
this.call.observer.emit('client-event', this, clientEvent);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const metaData of sample.clientMetaItems ?? []) {
|
|
225
|
+
this.addMetadata(metaData);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for (const issue of sample.clientIssues ?? []) {
|
|
229
|
+
this.addIssue(issue);
|
|
230
|
+
|
|
231
|
+
++this.deltaNumberOfIssues;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
for (const extensionStat of sample.extensionStats ?? []) {
|
|
235
|
+
this.addExtensionStats(extensionStat);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
for (const pcSample of sample.peerConnections ?? []) {
|
|
239
|
+
const observedPeerConnection = this._updatePeerConnection(pcSample);
|
|
240
|
+
|
|
241
|
+
if (!observedPeerConnection) continue;
|
|
242
|
+
|
|
243
|
+
this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
|
|
244
|
+
this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
|
|
245
|
+
this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
|
|
246
|
+
this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
|
|
247
|
+
this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
|
|
248
|
+
this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
|
|
249
|
+
this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
|
|
250
|
+
this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
|
|
251
|
+
this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
|
|
252
|
+
this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
|
|
253
|
+
this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
|
|
254
|
+
this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
|
|
255
|
+
this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
|
|
256
|
+
|
|
257
|
+
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
258
|
+
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
259
|
+
|
|
260
|
+
this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
|
|
261
|
+
this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
|
|
262
|
+
this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
|
|
263
|
+
this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
|
|
264
|
+
this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
|
|
265
|
+
|
|
266
|
+
if (observedPeerConnection.usingTURN) {
|
|
267
|
+
this.usingTURN = true;
|
|
268
|
+
}
|
|
269
|
+
if (observedPeerConnection.usingTCP) {
|
|
270
|
+
this.usingTCP = true;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (observedPeerConnection.currentRttInMs) {
|
|
274
|
+
if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
|
|
275
|
+
this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
|
|
276
|
+
}
|
|
277
|
+
if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
|
|
278
|
+
this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
|
|
279
|
+
}
|
|
280
|
+
if (observedPeerConnection.currentRttInMs < 50) {
|
|
281
|
+
this.deltaRttLt50Measurements += 1;
|
|
282
|
+
} else if (observedPeerConnection.currentRttInMs < 150) {
|
|
283
|
+
this.deltaRttLt150Measurements += 1;
|
|
284
|
+
} else if (observedPeerConnection.currentRttInMs < 300) {
|
|
285
|
+
this.deltaRttLt300Measurements += 1;
|
|
286
|
+
} else if (300 <= observedPeerConnection.currentRttInMs) {
|
|
287
|
+
this.deltaRttGtOrEq300Measurements += 1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
sumOfRtts += observedPeerConnection.currentRttInMs;
|
|
291
|
+
++numberOfRttMeasurements;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
for (const clientEvent of clientEventsPostBuffer) {
|
|
296
|
+
this._processClientEvent(clientEvent);
|
|
297
|
+
}
|
|
207
298
|
|
|
208
299
|
// emit new attachments?
|
|
209
300
|
this.attachments = sample.attachments;
|
|
@@ -225,12 +316,13 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
225
316
|
this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
|
|
226
317
|
this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
|
|
227
318
|
this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
|
|
228
|
-
this.
|
|
319
|
+
this.totalNumberOfIssues += this.deltaNumberOfIssues;
|
|
229
320
|
|
|
230
321
|
this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
|
|
231
322
|
this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
|
|
232
323
|
this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
|
|
233
324
|
this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
|
|
325
|
+
this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
|
|
234
326
|
|
|
235
327
|
this.calculatedScore.value = sample.score;
|
|
236
328
|
this.detectors.update();
|
|
@@ -249,7 +341,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
249
341
|
}
|
|
250
342
|
}
|
|
251
343
|
|
|
252
|
-
private _processClientEvent(event: ClientEvent) {
|
|
344
|
+
private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
|
|
253
345
|
// eslint-disable-next-line no-console
|
|
254
346
|
// console.warn('ClientEvent', event);
|
|
255
347
|
switch (event.type) {
|
|
@@ -278,9 +370,150 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
278
370
|
}
|
|
279
371
|
break;
|
|
280
372
|
}
|
|
373
|
+
case ClientEventTypes.PEER_CONNECTION_OPENED: {
|
|
374
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
375
|
+
|
|
376
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
377
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
378
|
+
|
|
379
|
+
if (observedPeerConnection) {
|
|
380
|
+
observedPeerConnection.openedAt = event.timestamp;
|
|
381
|
+
} else if (postBuffer) {
|
|
382
|
+
postBuffer.push(event);
|
|
383
|
+
} else {
|
|
384
|
+
logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection', event);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
case ClientEventTypes.PEER_CONNECTION_CLOSED: {
|
|
391
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
392
|
+
|
|
393
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
|
|
394
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
395
|
+
|
|
396
|
+
if (observedPeerConnection) {
|
|
397
|
+
observedPeerConnection.closedAt = event.timestamp;
|
|
398
|
+
} else if (postBuffer) {
|
|
399
|
+
postBuffer.push(event);
|
|
400
|
+
} else {
|
|
401
|
+
logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection', event);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
case ClientEventTypes.MEDIA_TRACK_ADDED: {
|
|
407
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
408
|
+
|
|
409
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
410
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
411
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
412
|
+
|
|
413
|
+
if (observedTrack) {
|
|
414
|
+
observedTrack.addedAt = event.timestamp;
|
|
415
|
+
} else if (postBuffer) {
|
|
416
|
+
postBuffer.push(event);
|
|
417
|
+
} else {
|
|
418
|
+
logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case ClientEventTypes.MEDIA_TRACK_REMOVED: {
|
|
424
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
425
|
+
|
|
426
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
|
|
427
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
428
|
+
const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
|
|
429
|
+
|
|
430
|
+
if (observedTrack) {
|
|
431
|
+
observedTrack.removedAt = event.timestamp;
|
|
432
|
+
} else if (postBuffer) {
|
|
433
|
+
postBuffer.push(event);
|
|
434
|
+
} else {
|
|
435
|
+
logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack', event);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
case ClientEventTypes.DATA_CHANNEL_OPEN: {
|
|
441
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
442
|
+
|
|
443
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
444
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
445
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
446
|
+
|
|
447
|
+
if (observedDataChannel) {
|
|
448
|
+
observedDataChannel.addedAt = event.timestamp;
|
|
449
|
+
} else if (postBuffer) {
|
|
450
|
+
postBuffer.push(event);
|
|
451
|
+
} else {
|
|
452
|
+
logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
case ClientEventTypes.DATA_CHANNEL_CLOSED: {
|
|
458
|
+
const payload = parseJsonAs<Record<string, unknown>>(event.payload);
|
|
459
|
+
|
|
460
|
+
if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
|
|
461
|
+
const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
|
|
462
|
+
const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
|
|
463
|
+
|
|
464
|
+
if (observedDataChannel) {
|
|
465
|
+
observedDataChannel.removedAt = event.timestamp;
|
|
466
|
+
} else if (postBuffer) {
|
|
467
|
+
postBuffer.push(event);
|
|
468
|
+
} else {
|
|
469
|
+
logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel', event);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
281
474
|
}
|
|
475
|
+
this.emit('clientEvent', event);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
public injectMetaData(metaData: ClientMetaData) {
|
|
479
|
+
if (this.closed) return;
|
|
480
|
+
|
|
481
|
+
if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
|
|
482
|
+
|
|
483
|
+
this._injections.clientMetaItems.push(metaData);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
public injectEvent(event: ClientEvent) {
|
|
487
|
+
if (this.closed) return;
|
|
488
|
+
|
|
489
|
+
if (!this._injections.clientEvents) this._injections.clientEvents = [];
|
|
490
|
+
|
|
491
|
+
this._injections.clientEvents.push(event);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
public injectIssue(issue: ClientIssue) {
|
|
495
|
+
if (this.closed) return;
|
|
496
|
+
|
|
497
|
+
if (!this._injections.clientIssues) this._injections.clientIssues = [];
|
|
498
|
+
|
|
499
|
+
this._injections.clientIssues.push(issue);
|
|
500
|
+
}
|
|
282
501
|
|
|
283
|
-
|
|
502
|
+
public injectExtensionStat(stat: ExtensionStat) {
|
|
503
|
+
if (this.closed) return;
|
|
504
|
+
|
|
505
|
+
if (!this._injections.extensionStats) this._injections.extensionStats = [];
|
|
506
|
+
|
|
507
|
+
this._injections.extensionStats.push(stat);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public injectAttachment(key: string, value: unknown) {
|
|
511
|
+
if (this.closed) return;
|
|
512
|
+
|
|
513
|
+
if (!this._injections.attachments) this._injections.attachments = {};
|
|
514
|
+
|
|
515
|
+
this._injections.attachments[key] = value;
|
|
516
|
+
|
|
284
517
|
}
|
|
285
518
|
|
|
286
519
|
public addMetadata(metadata: ClientMetaData) {
|
|
@@ -311,24 +544,24 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
311
544
|
public addIssue(issue: ClientIssue) {
|
|
312
545
|
if (this.closed) return;
|
|
313
546
|
|
|
314
|
-
++this.deltaNumberOfIssues;
|
|
315
547
|
this.emit('issue', issue);
|
|
316
548
|
this.call.observer.emit('client-issue', this, issue);
|
|
317
549
|
}
|
|
318
550
|
|
|
319
551
|
public addExtensionStats(stats: ExtensionStat) {
|
|
320
552
|
this.call.observer.emit('client-extension-stats', this, stats);
|
|
553
|
+
this.emit('extensionStats', stats);
|
|
321
554
|
}
|
|
322
555
|
|
|
323
|
-
private _updatePeerConnection(sample: PeerConnectionSample) {
|
|
556
|
+
private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
|
|
324
557
|
let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
|
|
325
558
|
|
|
326
559
|
if (!observedPeerConnection) {
|
|
327
560
|
if (!sample.peerConnectionId) {
|
|
328
|
-
return logger.warn(
|
|
561
|
+
return (logger.warn(
|
|
329
562
|
`ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
|
|
330
563
|
sample
|
|
331
|
-
);
|
|
564
|
+
), void 0);
|
|
332
565
|
}
|
|
333
566
|
|
|
334
567
|
observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
|
|
@@ -343,107 +576,95 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
343
576
|
|
|
344
577
|
observedPeerConnection.accept(sample);
|
|
345
578
|
|
|
346
|
-
observedPeerConnection
|
|
347
|
-
|
|
348
|
-
this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
|
|
349
|
-
this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
|
|
350
|
-
this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
|
|
351
|
-
this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
|
|
352
|
-
this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
|
|
353
|
-
this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
|
|
354
|
-
this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
|
|
355
|
-
this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
|
|
356
|
-
this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
|
|
357
|
-
this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
|
|
358
|
-
this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
|
|
359
|
-
this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
|
|
360
|
-
this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
|
|
361
|
-
|
|
362
|
-
this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
|
|
363
|
-
this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
|
|
364
|
-
|
|
365
|
-
this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
|
|
366
|
-
this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
|
|
367
|
-
this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
|
|
368
|
-
this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
|
|
369
|
-
this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
|
|
370
|
-
|
|
371
|
-
if (observedPeerConnection.currentRttInMs) {
|
|
372
|
-
this.deltaRttInMsMeasurements.push(observedPeerConnection.currentRttInMs);
|
|
373
|
-
}
|
|
579
|
+
return observedPeerConnection;
|
|
374
580
|
}
|
|
375
581
|
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
this.totalDataChannelBytesSent = 0;
|
|
379
|
-
this.totalDataChannelMessagesReceived = 0;
|
|
380
|
-
this.totalDataChannelMessagesSent = 0;
|
|
381
|
-
this.totalInboundPacketsLost = 0;
|
|
382
|
-
this.totalInboundPacketsReceived = 0;
|
|
383
|
-
this.totalOutboundPacketsSent = 0;
|
|
384
|
-
this.totalReceivedAudioBytes = 0;
|
|
385
|
-
this.totalReceivedVideoBytes = 0;
|
|
386
|
-
this.totalSentAudioBytes = 0;
|
|
387
|
-
this.totalSentVideoBytes = 0;
|
|
388
|
-
this.totalSentBytes = 0;
|
|
389
|
-
this.totalReceivedBytes = 0;
|
|
390
|
-
|
|
391
|
-
this.numberOfIssues = 0;
|
|
392
|
-
|
|
393
|
-
this.totalScoreSum = 0;
|
|
394
|
-
this.numberOfScoreMeasurements = 0;
|
|
395
|
-
}
|
|
582
|
+
private _mergeInjections(sample: ClientSample): ClientSample {
|
|
583
|
+
if (this.closed) return sample;
|
|
396
584
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
401
|
-
totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
402
|
-
totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
403
|
-
totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
|
|
404
|
-
totalDataChannelBytesSent: this.totalDataChannelBytesSent,
|
|
405
|
-
totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
|
|
406
|
-
totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
|
|
407
|
-
totalInboundPacketsLost: this.totalInboundPacketsLost,
|
|
408
|
-
totalInboundPacketsReceived: this.totalInboundPacketsReceived,
|
|
409
|
-
totalOutboundPacketsSent: this.totalOutboundPacketsSent,
|
|
410
|
-
totalReceivedAudioBytes: this.totalReceivedAudioBytes,
|
|
411
|
-
totalReceivedVideoBytes: this.totalReceivedVideoBytes,
|
|
412
|
-
totalSentAudioBytes: this.totalSentAudioBytes,
|
|
413
|
-
totalSentVideoBytes: this.totalSentVideoBytes,
|
|
414
|
-
totalSentBytes: this.totalSentBytes,
|
|
415
|
-
totalReceivedBytes: this.totalReceivedBytes,
|
|
585
|
+
if (this._injections.clientEvents) {
|
|
586
|
+
if (!sample.clientEvents) sample.clientEvents = [];
|
|
587
|
+
sample.clientEvents.push(...this._injections.clientEvents);
|
|
416
588
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
totalScoreSum: this.totalScoreSum,
|
|
420
|
-
numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
private _updateRttMeasurements() {
|
|
425
|
-
if (this.deltaRttInMsMeasurements.length < 1) {
|
|
426
|
-
this.currentRttInMs = undefined;
|
|
589
|
+
this._injections.clientEvents = undefined;
|
|
590
|
+
}
|
|
427
591
|
|
|
428
|
-
|
|
592
|
+
if (this._injections.clientIssues) {
|
|
593
|
+
if (!sample.clientIssues) sample.clientIssues = [];
|
|
594
|
+
sample.clientIssues.push(...this._injections.clientIssues);
|
|
595
|
+
|
|
596
|
+
this._injections.clientIssues = undefined;
|
|
429
597
|
}
|
|
430
|
-
this.currentRttInMs = getMedian(this.deltaRttInMsMeasurements, false);
|
|
431
598
|
|
|
432
|
-
if (this.
|
|
433
|
-
|
|
434
|
-
this.
|
|
599
|
+
if (this._injections.extensionStats) {
|
|
600
|
+
if (!sample.extensionStats) sample.extensionStats = [];
|
|
601
|
+
sample.extensionStats.push(...this._injections.extensionStats);
|
|
602
|
+
|
|
603
|
+
this._injections.extensionStats = undefined;
|
|
604
|
+
}
|
|
435
605
|
|
|
436
|
-
|
|
606
|
+
if (this._injections.attachments) {
|
|
607
|
+
if (!sample.attachments) sample.attachments = {};
|
|
608
|
+
Object.assign(sample.attachments, this._injections.attachments);
|
|
609
|
+
|
|
610
|
+
this._injections.attachments = undefined;
|
|
437
611
|
}
|
|
438
|
-
|
|
439
|
-
if (this.
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
this.deltaRttLt300Measurements += 1;
|
|
445
|
-
} else if (300 <= this.currentRttInMs) {
|
|
446
|
-
this.deltaRttGtOrEq300Measurements += 1;
|
|
612
|
+
|
|
613
|
+
if (this._injections.clientMetaItems) {
|
|
614
|
+
if (!sample.clientMetaItems) sample.clientMetaItems = [];
|
|
615
|
+
sample.clientMetaItems.push(...this._injections.clientMetaItems);
|
|
616
|
+
|
|
617
|
+
this._injections.clientMetaItems = undefined;
|
|
447
618
|
}
|
|
619
|
+
|
|
620
|
+
return sample;
|
|
448
621
|
}
|
|
622
|
+
|
|
623
|
+
// public resetSummaryMetrics() {
|
|
624
|
+
// this.totalDataChannelBytesReceived = 0;
|
|
625
|
+
// this.totalDataChannelBytesSent = 0;
|
|
626
|
+
// this.totalDataChannelMessagesReceived = 0;
|
|
627
|
+
// this.totalDataChannelMessagesSent = 0;
|
|
628
|
+
// this.totalInboundPacketsLost = 0;
|
|
629
|
+
// this.totalInboundPacketsReceived = 0;
|
|
630
|
+
// this.totalOutboundPacketsSent = 0;
|
|
631
|
+
// this.totalReceivedAudioBytes = 0;
|
|
632
|
+
// this.totalReceivedVideoBytes = 0;
|
|
633
|
+
// this.totalSentAudioBytes = 0;
|
|
634
|
+
// this.totalSentVideoBytes = 0;
|
|
635
|
+
// this.totalSentBytes = 0;
|
|
636
|
+
// this.totalReceivedBytes = 0;
|
|
637
|
+
|
|
638
|
+
// this.totalNumberOfIssues = 0;
|
|
639
|
+
|
|
640
|
+
// this.totalScoreSum = 0;
|
|
641
|
+
// this.numberOfScoreMeasurements = 0;
|
|
642
|
+
// }
|
|
643
|
+
|
|
644
|
+
// public createSummary(): ObservedClientSummary {
|
|
645
|
+
// return {
|
|
646
|
+
// totalRttLt50Measurements: this.totalRttLt50Measurements,
|
|
647
|
+
// totalRttLt150Measurements: this.totalRttLt150Measurements,
|
|
648
|
+
// totalRttLt300Measurements: this.totalRttLt300Measurements,
|
|
649
|
+
// totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
|
|
650
|
+
// totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
|
|
651
|
+
// totalDataChannelBytesSent: this.totalDataChannelBytesSent,
|
|
652
|
+
// totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
|
|
653
|
+
// totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
|
|
654
|
+
// totalInboundPacketsLost: this.totalInboundPacketsLost,
|
|
655
|
+
// totalInboundPacketsReceived: this.totalInboundPacketsReceived,
|
|
656
|
+
// totalOutboundPacketsSent: this.totalOutboundPacketsSent,
|
|
657
|
+
// totalReceivedAudioBytes: this.totalReceivedAudioBytes,
|
|
658
|
+
// totalReceivedVideoBytes: this.totalReceivedVideoBytes,
|
|
659
|
+
// totalSentAudioBytes: this.totalSentAudioBytes,
|
|
660
|
+
// totalSentVideoBytes: this.totalSentVideoBytes,
|
|
661
|
+
// totalSentBytes: this.totalSentBytes,
|
|
662
|
+
// totalReceivedBytes: this.totalReceivedBytes,
|
|
663
|
+
|
|
664
|
+
// numberOfIssues: this.totalNumberOfIssues,
|
|
665
|
+
|
|
666
|
+
// totalScoreSum: this.totalScoreSum,
|
|
667
|
+
// numberOfScoreMeasurements: this.numberOfScoreMeasurements,
|
|
668
|
+
// };
|
|
669
|
+
// }
|
|
449
670
|
}
|