@observertc/observer-js 0.30.6-beta → 0.40.0-beta
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 +6 -13
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +24 -104
- package/lib/ObservedClient.d.ts +16 -27
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +360 -523
- package/lib/ObservedInboundTrack.d.ts +3 -8
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +74 -154
- package/lib/ObservedOutboundTrack.d.ts +9 -8
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +76 -130
- package/lib/ObservedPeerConnection.d.ts +17 -15
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +64 -173
- package/lib/ObservedSfu.d.ts +5 -7
- package/lib/ObservedSfu.d.ts.map +1 -1
- package/lib/ObservedSfu.js +10 -74
- package/lib/Observer.d.ts +5 -6
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +28 -31
- package/lib/common/types.d.ts +0 -55
- package/lib/common/types.d.ts.map +1 -1
- package/lib/index.d.ts +5 -7
- package/lib/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ObservedCall.ts +27 -87
- package/src/ObservedClient.ts +425 -582
- package/src/ObservedInboundTrack.ts +14 -65
- package/src/ObservedOutboundTrack.ts +32 -53
- package/src/ObservedPeerConnection.ts +55 -117
- package/src/ObservedSfu.ts +11 -46
- package/src/Observer.ts +11 -16
- package/src/common/types.ts +0 -69
- package/src/index.ts +5 -7
- package/lib/models/Models.d.ts +0 -642
- package/lib/models/Models.d.ts.map +0 -1
- package/lib/models/Models.js +0 -481
- package/lib/models/samples_pb.d.ts +0 -2452
- package/lib/models/samples_pb.d.ts.map +0 -1
- package/lib/models/samples_pb.js +0 -1495
- package/lib/storages/ObserverStorage.d.ts +0 -87
- package/lib/storages/ObserverStorage.d.ts.map +0 -1
- package/lib/storages/ObserverStorage.js +0 -2
- package/lib/storages/SimpleStorage.d.ts +0 -19
- package/lib/storages/SimpleStorage.d.ts.map +0 -1
- package/lib/storages/SimpleStorage.js +0 -106
- package/lib/storages/StorageProvider.d.ts +0 -16
- package/lib/storages/StorageProvider.d.ts.map +0 -1
- package/lib/storages/StorageProvider.js +0 -29
- package/src/models/Models.ts +0 -1103
- package/src/models/samples_pb.ts +0 -4061
- package/src/storages/ObserverStorage.ts +0 -99
- package/src/storages/SimpleStorage.ts +0 -120
- package/src/storages/StorageProvider.ts +0 -42
package/src/ObservedClient.ts
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import { ClientSample, IceLocalCandidate, IceRemoteCandidate } from '@observertc/sample-schemas-js';
|
|
1
|
+
import { Browser, ClientSample, Engine, IceLocalCandidate, IceRemoteCandidate, OperationSystem, Platform } from '@observertc/sample-schemas-js';
|
|
2
2
|
import { ObservedCall } from './ObservedCall';
|
|
3
|
-
import * as Models from './models/Models';
|
|
4
|
-
import { StorageProvider } from './storages/StorageProvider';
|
|
5
3
|
import { EventEmitter } from 'events';
|
|
6
|
-
import { createSingleExecutor } from './common/SingleExecutor';
|
|
7
4
|
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
8
5
|
import { createLogger } from './common/logger';
|
|
9
6
|
import { CallMetaType, createCallMetaReport } from './common/callMetaReports';
|
|
10
7
|
// eslint-disable-next-line camelcase
|
|
11
|
-
import { Samples_ClientSample_Browser, Samples_ClientSample_Engine, Samples_ClientSample_OperationSystem, Samples_ClientSample_Platform } from './models/samples_pb';
|
|
12
8
|
import { isValidUuid } from './common/utils';
|
|
13
|
-
import {
|
|
9
|
+
import { createClientLeftEventReport } from './common/callEventReports';
|
|
14
10
|
import { CallEventType } from './common/CallEventType';
|
|
15
11
|
|
|
16
12
|
const logger = createLogger('ObservedClient');
|
|
17
13
|
|
|
18
|
-
export type
|
|
19
|
-
callId: string;
|
|
14
|
+
export type ObservedClientModel= {
|
|
20
15
|
clientId: string;
|
|
21
16
|
mediaUnitId: string;
|
|
22
|
-
appData: AppData;
|
|
23
17
|
overflowingProcessingThreshold?: number;
|
|
24
|
-
|
|
18
|
+
userId?: string,
|
|
19
|
+
marker?: string,
|
|
20
|
+
operationSystem?: OperationSystem,
|
|
21
|
+
engine?: Engine,
|
|
22
|
+
platform?: Platform,
|
|
23
|
+
browser?: Browser,
|
|
25
24
|
|
|
26
25
|
/**
|
|
27
26
|
* before client-monitor-js 3.4.0 the client joined event was generated by the observer, this flag is to keep the compatibility with the old behavior
|
|
@@ -32,7 +31,6 @@ export type ObservedClientConfig<AppData extends Record<string, unknown> = Recor
|
|
|
32
31
|
export type ObservedClientEvents = {
|
|
33
32
|
update: [],
|
|
34
33
|
close: [],
|
|
35
|
-
'processing-sample-overflow': [],
|
|
36
34
|
newpeerconnection: [ObservedPeerConnection],
|
|
37
35
|
iceconnectionstatechange: [{
|
|
38
36
|
peerConnection: ObservedPeerConnection,
|
|
@@ -63,61 +61,18 @@ export declare interface ObservedClient<AppData extends Record<string, unknown>
|
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
storageProvider: StorageProvider,
|
|
70
|
-
) {
|
|
71
|
-
const { callId, clientId, mediaUnitId } = config;
|
|
72
|
-
|
|
73
|
-
const model = new Models.Client({
|
|
74
|
-
roomId: call.roomId,
|
|
75
|
-
serviceId: call.serviceId,
|
|
76
|
-
callId,
|
|
77
|
-
clientId,
|
|
78
|
-
mediaUnitId,
|
|
79
|
-
peerConnectionIds: [],
|
|
80
|
-
joined: BigInt(config.joined ?? Date.now()),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const result = new ObservedClient<T>(model, call, storageProvider, config.appData);
|
|
84
|
-
|
|
85
|
-
const alreadyInserted = await storageProvider.clientStorage.insert(clientId, model);
|
|
86
|
-
|
|
87
|
-
if (alreadyInserted) throw new Error(`Client with id ${clientId} already exists`);
|
|
88
|
-
|
|
89
|
-
result._overflowingProcessingThreshold = config.overflowingProcessingThreshold ?? 0;
|
|
90
|
-
|
|
91
|
-
if (config.addJoinAndDetachClientEvent) {
|
|
92
|
-
call.reports.addCallEventReport(createClientJoinedEventReport(
|
|
93
|
-
call.serviceId,
|
|
94
|
-
result.mediaUnitId,
|
|
95
|
-
call.roomId,
|
|
96
|
-
call.callId,
|
|
97
|
-
result.clientId,
|
|
98
|
-
result.joined,
|
|
99
|
-
result.userId,
|
|
100
|
-
result.marker,
|
|
101
|
-
));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return result;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public created = Date.now();
|
|
64
|
+
|
|
65
|
+
public readonly created = Date.now();
|
|
66
|
+
public _updated = Date.now();
|
|
108
67
|
|
|
109
68
|
private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
|
|
110
|
-
private readonly _execute = createSingleExecutor();
|
|
111
69
|
|
|
112
|
-
private _overflowingProcessingThreshold = 0;
|
|
113
70
|
private _closed = false;
|
|
114
|
-
|
|
71
|
+
|
|
115
72
|
private _acceptedSample = 0;
|
|
116
|
-
private _processingSample = 0;
|
|
117
73
|
private _timeZoneOffsetInHours?: number;
|
|
118
74
|
private _left?: number;
|
|
119
|
-
|
|
120
|
-
|
|
75
|
+
|
|
121
76
|
public usingTURN = false;
|
|
122
77
|
public availableOutgoingBitrate = 0;
|
|
123
78
|
public availableIncomingBitrate = 0;
|
|
@@ -140,20 +95,14 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
140
95
|
public readonly ωpendingCreatedTracksTimestamp = new Map<string, number>();
|
|
141
96
|
public readonly ωpendingCreatedPeerConnectionTimestamp = new Map<string, number>();
|
|
142
97
|
|
|
143
|
-
|
|
144
|
-
private readonly _model:
|
|
98
|
+
public constructor(
|
|
99
|
+
private readonly _model: ObservedClientModel,
|
|
145
100
|
public readonly call: ObservedCall,
|
|
146
|
-
private readonly _storageProvider: StorageProvider,
|
|
147
101
|
public readonly appData: AppData
|
|
148
102
|
) {
|
|
149
103
|
super();
|
|
150
104
|
}
|
|
151
105
|
|
|
152
|
-
public get joined(): number {
|
|
153
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
154
|
-
return Number(this._model.joined!);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
106
|
public get clientId(): string {
|
|
158
107
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
159
108
|
return this._model.clientId!;
|
|
@@ -161,17 +110,17 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
161
110
|
|
|
162
111
|
public get roomId() {
|
|
163
112
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
164
|
-
return this.
|
|
113
|
+
return this.call.roomId!;
|
|
165
114
|
}
|
|
166
115
|
|
|
167
116
|
public get serviceId() {
|
|
168
117
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
169
|
-
return this.
|
|
118
|
+
return this.call.serviceId!;
|
|
170
119
|
}
|
|
171
120
|
|
|
172
121
|
public get callId() {
|
|
173
122
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
174
|
-
return this.
|
|
123
|
+
return this.call.callId!;
|
|
175
124
|
}
|
|
176
125
|
|
|
177
126
|
public get mediaUnitId() {
|
|
@@ -219,20 +168,6 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
219
168
|
return this._updated;
|
|
220
169
|
}
|
|
221
170
|
|
|
222
|
-
public get numberOfAcceptedUpdates() {
|
|
223
|
-
return this._numberOfAcceptedUpdates;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
public get uptimeInMs() {
|
|
227
|
-
return this._updated - this.created;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
public get durationInMs(): number | undefined {
|
|
231
|
-
if (!this._left) return;
|
|
232
|
-
|
|
233
|
-
return this._left - this.joined;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
171
|
public get closed() {
|
|
237
172
|
return this._closed;
|
|
238
173
|
}
|
|
@@ -245,600 +180,518 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
245
180
|
if (this._closed) return;
|
|
246
181
|
this._closed = true;
|
|
247
182
|
|
|
248
|
-
!this._left
|
|
183
|
+
if (!this._left) {
|
|
184
|
+
this._addClientLeftReport();
|
|
185
|
+
}
|
|
249
186
|
|
|
250
187
|
Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
|
|
251
188
|
|
|
252
|
-
this.
|
|
253
|
-
.catch(() => void 0)
|
|
254
|
-
.finally(() => this.emit('close'));
|
|
189
|
+
this.emit('close');
|
|
255
190
|
}
|
|
256
191
|
|
|
257
|
-
public
|
|
192
|
+
public accept(sample: ClientSample): void {
|
|
258
193
|
if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
259
194
|
if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
|
|
260
195
|
throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
|
|
261
196
|
}
|
|
262
197
|
++this._acceptedSample;
|
|
263
|
-
++this._processingSample;
|
|
264
198
|
|
|
265
|
-
|
|
266
|
-
|
|
199
|
+
for (const peerConnection of this._peerConnections.values()) {
|
|
200
|
+
if (peerConnection.closed) continue;
|
|
201
|
+
peerConnection.resetMetrics();
|
|
267
202
|
}
|
|
268
203
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
let executeSave = false;
|
|
278
|
-
|
|
279
|
-
if (this.userId !== sample.userId) {
|
|
280
|
-
this._model.userId = sample.userId;
|
|
281
|
-
executeSave = true;
|
|
282
|
-
}
|
|
283
|
-
if (this._model.marker !== sample.marker) {
|
|
284
|
-
this._model.marker = sample.marker;
|
|
285
|
-
executeSave = true;
|
|
286
|
-
}
|
|
204
|
+
if (this.userId !== sample.userId) {
|
|
205
|
+
this._model.userId = sample.userId;
|
|
206
|
+
}
|
|
207
|
+
if (this._model.marker !== sample.marker) {
|
|
208
|
+
this._model.marker = sample.marker;
|
|
209
|
+
}
|
|
287
210
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
211
|
+
if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
|
|
212
|
+
this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
|
|
213
|
+
}
|
|
292
214
|
|
|
293
|
-
|
|
294
|
-
|
|
215
|
+
if (sample.os && (
|
|
216
|
+
this._model.operationSystem?.name !== sample.os.name ||
|
|
295
217
|
this._model.operationSystem?.version !== sample.os.version ||
|
|
296
218
|
this._model.operationSystem?.versionName !== sample.os.versionName
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
...sample.os,
|
|
300
|
-
});
|
|
219
|
+
)) {
|
|
220
|
+
this._model.operationSystem = sample.os;
|
|
301
221
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
222
|
+
const callMetaReport = createCallMetaReport(
|
|
223
|
+
this.serviceId,
|
|
224
|
+
this.mediaUnitId,
|
|
225
|
+
this.roomId,
|
|
226
|
+
this.callId,
|
|
227
|
+
this.clientId,
|
|
228
|
+
{
|
|
229
|
+
type: CallMetaType.OPERATION_SYSTEM,
|
|
230
|
+
payload: sample.os,
|
|
231
|
+
}, this.userId);
|
|
312
232
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
233
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
234
|
+
}
|
|
316
235
|
|
|
317
|
-
|
|
318
|
-
|
|
236
|
+
if (sample.engine && (
|
|
237
|
+
this._model.engine?.name !== sample.engine.name ||
|
|
319
238
|
this._model.engine?.version !== sample.engine.version
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
...sample.engine,
|
|
323
|
-
});
|
|
239
|
+
)) {
|
|
240
|
+
this._model.engine = sample.engine;
|
|
324
241
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
242
|
+
const callMetaReport = createCallMetaReport(
|
|
243
|
+
this.serviceId,
|
|
244
|
+
this.mediaUnitId,
|
|
245
|
+
this.roomId,
|
|
246
|
+
this.callId,
|
|
247
|
+
this.clientId,
|
|
248
|
+
{
|
|
249
|
+
type: CallMetaType.ENGINE,
|
|
250
|
+
payload: sample.engine,
|
|
251
|
+
}, this.userId);
|
|
335
252
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
253
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
254
|
+
}
|
|
339
255
|
|
|
340
|
-
|
|
341
|
-
|
|
256
|
+
if (sample.platform && (
|
|
257
|
+
this._model.platform?.model !== sample.platform.model ||
|
|
342
258
|
this._model.platform?.type !== sample.platform.type ||
|
|
343
259
|
this._model.platform?.vendor !== sample.platform.vendor
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
...sample.platform,
|
|
347
|
-
});
|
|
260
|
+
)) {
|
|
261
|
+
this._model.platform = sample.platform;
|
|
348
262
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
263
|
+
const callMetaReport = createCallMetaReport(
|
|
264
|
+
this.serviceId,
|
|
265
|
+
this.mediaUnitId,
|
|
266
|
+
this.roomId,
|
|
267
|
+
this.callId,
|
|
268
|
+
this.clientId,
|
|
269
|
+
{
|
|
270
|
+
type: CallMetaType.PLATFORM,
|
|
271
|
+
payload: sample.platform,
|
|
272
|
+
}, this.userId);
|
|
359
273
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
}
|
|
274
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
275
|
+
}
|
|
363
276
|
|
|
364
|
-
|
|
365
|
-
|
|
277
|
+
if (sample.browser && (
|
|
278
|
+
this._model.browser?.name !== sample.browser.name ||
|
|
366
279
|
this._model.browser?.version !== sample.browser.version
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
...sample.browser,
|
|
370
|
-
});
|
|
280
|
+
)) {
|
|
281
|
+
this._model.browser = sample.browser;
|
|
371
282
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
283
|
+
const callMetaReport = createCallMetaReport(
|
|
284
|
+
this.serviceId,
|
|
285
|
+
this.mediaUnitId,
|
|
286
|
+
this.roomId,
|
|
287
|
+
this.callId,
|
|
288
|
+
this.clientId,
|
|
289
|
+
{
|
|
290
|
+
type: CallMetaType.BROWSER,
|
|
291
|
+
payload: sample.browser,
|
|
292
|
+
}, this.userId);
|
|
382
293
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
for (const mediaConstraint of sample.mediaConstraints ?? []) {
|
|
388
|
-
const callMetaReport = createCallMetaReport(
|
|
389
|
-
this.serviceId,
|
|
390
|
-
this.mediaUnitId,
|
|
391
|
-
this.roomId,
|
|
392
|
-
this.callId,
|
|
393
|
-
this.clientId,
|
|
394
|
-
{
|
|
395
|
-
type: CallMetaType.MEDIA_CONSTRAINT,
|
|
396
|
-
payload: mediaConstraint,
|
|
397
|
-
}, this.userId);
|
|
398
|
-
|
|
399
|
-
this.reports.addCallMetaReport(callMetaReport);
|
|
400
|
-
}
|
|
294
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
295
|
+
}
|
|
401
296
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
297
|
+
for (const mediaConstraint of sample.mediaConstraints ?? []) {
|
|
298
|
+
const callMetaReport = createCallMetaReport(
|
|
299
|
+
this.serviceId,
|
|
300
|
+
this.mediaUnitId,
|
|
301
|
+
this.roomId,
|
|
302
|
+
this.callId,
|
|
303
|
+
this.clientId,
|
|
304
|
+
{
|
|
305
|
+
type: CallMetaType.MEDIA_CONSTRAINT,
|
|
306
|
+
payload: mediaConstraint,
|
|
307
|
+
}, this.userId);
|
|
308
|
+
|
|
309
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
310
|
+
}
|
|
416
311
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
payload:
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
312
|
+
for (const localSDP of sample.localSDPs ?? []) {
|
|
313
|
+
const callMetaReport = createCallMetaReport(
|
|
314
|
+
this.serviceId,
|
|
315
|
+
this.mediaUnitId,
|
|
316
|
+
this.roomId,
|
|
317
|
+
this.callId,
|
|
318
|
+
this.clientId,
|
|
319
|
+
{
|
|
320
|
+
type: CallMetaType.LOCAL_SDP,
|
|
321
|
+
payload: localSDP,
|
|
322
|
+
}, this.userId);
|
|
323
|
+
|
|
324
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
325
|
+
}
|
|
430
326
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
this._left = timestamp ?? Date.now();
|
|
445
|
-
break;
|
|
446
|
-
case CallEventType.ICE_CONNECTION_STATE_CHANGED:
|
|
447
|
-
peerConnection && callEvent.value && this.emit('iceconnectionstatechange', {
|
|
448
|
-
peerConnection,
|
|
449
|
-
state: callEvent.value,
|
|
450
|
-
});
|
|
451
|
-
break;
|
|
452
|
-
case CallEventType.ICE_GATHERING_STATE_CHANGED:
|
|
453
|
-
peerConnection && callEvent.value && this.emit('icegatheringstatechange', {
|
|
454
|
-
peerConnection,
|
|
455
|
-
state: callEvent.value,
|
|
456
|
-
});
|
|
457
|
-
break;
|
|
458
|
-
case CallEventType.PEER_CONNECTION_STATE_CHANGED:
|
|
459
|
-
peerConnection && callEvent.value && this.emit('connectionstatechange', {
|
|
460
|
-
peerConnection,
|
|
461
|
-
state: callEvent.value,
|
|
462
|
-
});
|
|
463
|
-
break;
|
|
464
|
-
case CallEventType.PEER_CONNECTION_OPENED: {
|
|
465
|
-
if (!callEvent.peerConnectionId) break;
|
|
466
|
-
if (peerConnection) {
|
|
467
|
-
peerConnection.created = timestamp ?? peerConnection.created;
|
|
468
|
-
} else {
|
|
469
|
-
this.ωpendingCreatedPeerConnectionTimestamp.set(callEvent.peerConnectionId, timestamp ?? Date.now());
|
|
470
|
-
}
|
|
471
|
-
break;
|
|
472
|
-
}
|
|
473
|
-
case CallEventType.MEDIA_TRACK_ADDED: {
|
|
474
|
-
if (!callEvent.mediaTrackId) break;
|
|
475
|
-
const track = peerConnection?.getTrack(callEvent.mediaTrackId);
|
|
476
|
-
|
|
477
|
-
if (track) {
|
|
478
|
-
track.created = timestamp ?? track.created;
|
|
479
|
-
} else {
|
|
480
|
-
this.ωpendingCreatedTracksTimestamp.set(callEvent.mediaTrackId, timestamp ?? Date.now());
|
|
481
|
-
}
|
|
482
|
-
}
|
|
327
|
+
for (const extensionStats of sample.extensionStats ?? []) {
|
|
328
|
+
this.reports.addClientExtensionReport({
|
|
329
|
+
serviceId: this.serviceId,
|
|
330
|
+
mediaUnitId: this.mediaUnitId,
|
|
331
|
+
roomId: this.roomId,
|
|
332
|
+
callId: this.callId,
|
|
333
|
+
clientId: this.clientId,
|
|
334
|
+
userId: this.userId,
|
|
335
|
+
timestamp: Date.now(),
|
|
336
|
+
payload: extensionStats.payload,
|
|
337
|
+
extensionType: extensionStats.type,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
483
340
|
|
|
341
|
+
for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
|
|
342
|
+
switch (callEvent.name) {
|
|
343
|
+
case CallEventType.CLIENT_LEFT: {
|
|
344
|
+
this._left = timestamp;
|
|
345
|
+
break;
|
|
484
346
|
}
|
|
485
|
-
|
|
486
|
-
this.reports.addCallEventReport({
|
|
487
|
-
serviceId: this.serviceId,
|
|
488
|
-
mediaUnitId: this.mediaUnitId,
|
|
489
|
-
roomId: this.roomId,
|
|
490
|
-
callId: this.callId,
|
|
491
|
-
clientId: this.clientId,
|
|
492
|
-
userId: this.userId,
|
|
493
|
-
timestamp: timestamp ?? Date.now(),
|
|
494
|
-
...callEvent,
|
|
495
|
-
});
|
|
496
347
|
}
|
|
348
|
+
this.reports.addCallEventReport({
|
|
349
|
+
serviceId: this.serviceId,
|
|
350
|
+
mediaUnitId: this.mediaUnitId,
|
|
351
|
+
roomId: this.roomId,
|
|
352
|
+
callId: this.callId,
|
|
353
|
+
clientId: this.clientId,
|
|
354
|
+
userId: this.userId,
|
|
355
|
+
timestamp: timestamp ?? Date.now(),
|
|
356
|
+
...callEvent,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
497
359
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
360
|
+
for (const userMediaError of sample.userMediaErrors ?? []) {
|
|
361
|
+
const callMetaReport = createCallMetaReport(
|
|
362
|
+
this.serviceId,
|
|
363
|
+
this.mediaUnitId,
|
|
364
|
+
this.roomId,
|
|
365
|
+
this.callId,
|
|
366
|
+
this.clientId, {
|
|
367
|
+
type: CallMetaType.USER_MEDIA_ERROR,
|
|
368
|
+
payload: userMediaError,
|
|
369
|
+
}, this.userId);
|
|
370
|
+
|
|
371
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
372
|
+
this.userMediaErrors.push(userMediaError);
|
|
373
|
+
}
|
|
512
374
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
375
|
+
for (const certificate of sample.certificates ?? []) {
|
|
376
|
+
const callMetaReport = createCallMetaReport(
|
|
377
|
+
this.serviceId,
|
|
378
|
+
this.mediaUnitId,
|
|
379
|
+
this.roomId,
|
|
380
|
+
this.callId,
|
|
381
|
+
this.clientId, {
|
|
382
|
+
type: CallMetaType.CERTIFICATE,
|
|
383
|
+
payload: certificate,
|
|
384
|
+
}, this.userId);
|
|
385
|
+
|
|
386
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
387
|
+
}
|
|
526
388
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
389
|
+
for (const codec of sample.codecs ?? []) {
|
|
390
|
+
const callMetaReport = createCallMetaReport(
|
|
391
|
+
this.serviceId,
|
|
392
|
+
this.mediaUnitId,
|
|
393
|
+
this.roomId,
|
|
394
|
+
this.callId,
|
|
395
|
+
this.clientId, {
|
|
396
|
+
type: CallMetaType.CODEC,
|
|
397
|
+
payload: codec,
|
|
398
|
+
}, this.userId);
|
|
399
|
+
|
|
400
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
401
|
+
codec.mimeType && this.codecs.push(codec.mimeType);
|
|
402
|
+
}
|
|
541
403
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
404
|
+
for (const iceServer of sample.iceServers ?? []) {
|
|
405
|
+
const callMetaReport = createCallMetaReport(
|
|
406
|
+
this.serviceId,
|
|
407
|
+
this.mediaUnitId,
|
|
408
|
+
this.roomId,
|
|
409
|
+
this.callId,
|
|
410
|
+
this.clientId, {
|
|
411
|
+
type: CallMetaType.ICE_SERVER,
|
|
412
|
+
payload: iceServer,
|
|
413
|
+
}, this.userId);
|
|
414
|
+
|
|
415
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
416
|
+
}
|
|
555
417
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
418
|
+
for (const mediaDevice of sample.mediaDevices ?? []) {
|
|
419
|
+
const callMetaReport = createCallMetaReport(
|
|
420
|
+
this.serviceId,
|
|
421
|
+
this.mediaUnitId,
|
|
422
|
+
this.roomId,
|
|
423
|
+
this.callId,
|
|
424
|
+
this.clientId, {
|
|
425
|
+
type: CallMetaType.MEDIA_DEVICE,
|
|
426
|
+
payload: mediaDevice,
|
|
427
|
+
}, this.userId);
|
|
428
|
+
|
|
429
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
430
|
+
mediaDevice.label && this.mediaDevices.push(mediaDevice.label);
|
|
431
|
+
}
|
|
570
432
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
433
|
+
for (const mediaSource of sample.mediaSources ?? []) {
|
|
434
|
+
const callMetaReport = createCallMetaReport(
|
|
435
|
+
this.serviceId,
|
|
436
|
+
this.mediaUnitId,
|
|
437
|
+
this.roomId,
|
|
438
|
+
this.callId,
|
|
439
|
+
this.clientId, {
|
|
440
|
+
type: CallMetaType.MEDIA_SOURCE,
|
|
441
|
+
payload: mediaSource,
|
|
442
|
+
}, this.userId);
|
|
443
|
+
|
|
444
|
+
this.reports.addCallMetaReport(callMetaReport);
|
|
445
|
+
}
|
|
584
446
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
447
|
+
for (const transport of sample.pcTransports ?? []) {
|
|
448
|
+
try {
|
|
449
|
+
const peerConnection = this._peerConnections.get(transport.transportId) ?? this._createPeerConnection(transport.peerConnectionId);
|
|
588
450
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
}
|
|
593
|
-
|
|
451
|
+
!peerConnection.label && transport.label && (peerConnection.label = transport.label);
|
|
452
|
+
peerConnection.update(transport, sample.timestamp);
|
|
453
|
+
} catch (err) {
|
|
454
|
+
logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
|
|
594
455
|
}
|
|
456
|
+
|
|
457
|
+
}
|
|
595
458
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
459
|
+
for (const track of sample.inboundAudioTracks ?? []) {
|
|
460
|
+
if (!track.peerConnectionId || !track.trackId) {
|
|
461
|
+
logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
599
462
|
|
|
600
|
-
|
|
601
|
-
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
602
465
|
|
|
603
|
-
|
|
604
|
-
|
|
466
|
+
try {
|
|
467
|
+
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
605
468
|
|
|
606
|
-
|
|
469
|
+
if (!peerConnection) continue;
|
|
607
470
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
471
|
+
const inboundAudioTrack = peerConnection.inboundAudioTracks.get(track.trackId) ?? peerConnection.createInboundAudioTrack({
|
|
472
|
+
trackId: track.trackId,
|
|
473
|
+
sfuStreamId: track.sfuStreamId,
|
|
474
|
+
sfuSinkId: track.sfuSinkId,
|
|
475
|
+
});
|
|
613
476
|
|
|
614
|
-
|
|
477
|
+
inboundAudioTrack.update(track, sample.timestamp);
|
|
615
478
|
|
|
616
|
-
|
|
479
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(track.sfuStreamId ?? '');
|
|
617
480
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
}
|
|
621
|
-
} catch (err) {
|
|
622
|
-
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
481
|
+
if (remoteOutboundTrack && inboundAudioTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundAudioTrack.sfuStreamId)) {
|
|
482
|
+
remoteOutboundTrack.connectInboundTrack(inboundAudioTrack);
|
|
623
483
|
}
|
|
484
|
+
} catch (err) {
|
|
485
|
+
logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
|
|
624
486
|
}
|
|
487
|
+
}
|
|
625
488
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
489
|
+
for (const track of sample.inboundVideoTracks ?? []) {
|
|
490
|
+
if (!track.peerConnectionId || !track.trackId) {
|
|
491
|
+
logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
629
492
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (isValidUuid(track.trackId) === false) {
|
|
496
|
+
// mediasoup-probator trackId is not a valid UUID, no need to warn about it
|
|
497
|
+
if (track.trackId === 'probator') continue;
|
|
498
|
+
logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
638
501
|
|
|
639
|
-
|
|
640
|
-
|
|
502
|
+
try {
|
|
503
|
+
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
641
504
|
|
|
642
|
-
|
|
505
|
+
if (!peerConnection) continue;
|
|
643
506
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
507
|
+
const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? peerConnection.createInboundVideoTrack({
|
|
508
|
+
trackId: track.trackId,
|
|
509
|
+
sfuStreamId: track.sfuStreamId,
|
|
510
|
+
sfuSinkId: track.sfuSinkId,
|
|
511
|
+
});
|
|
649
512
|
|
|
650
|
-
|
|
513
|
+
inboundVideoTrack.update(track, sample.timestamp);
|
|
651
514
|
|
|
652
|
-
|
|
515
|
+
const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
|
|
653
516
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
} catch (err) {
|
|
658
|
-
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
517
|
+
if (remoteOutboundTrack && inboundVideoTrack.sfuStreamId && !remoteOutboundTrack.remoteInboundTracks.has(inboundVideoTrack.sfuStreamId)) {
|
|
518
|
+
remoteOutboundTrack.connectInboundTrack(inboundVideoTrack);
|
|
659
519
|
}
|
|
520
|
+
} catch (err) {
|
|
521
|
+
logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
|
|
660
522
|
}
|
|
523
|
+
}
|
|
661
524
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
525
|
+
for (const track of sample.outboundAudioTracks ?? []) {
|
|
526
|
+
if (!track.peerConnectionId || !track.trackId) {
|
|
527
|
+
logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
665
528
|
|
|
666
|
-
|
|
667
|
-
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
668
531
|
|
|
669
|
-
|
|
670
|
-
|
|
532
|
+
try {
|
|
533
|
+
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
671
534
|
|
|
672
|
-
|
|
535
|
+
if (!peerConnection) continue;
|
|
673
536
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
|
|
537
|
+
const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? peerConnection.createOutboundAudioTrack({
|
|
538
|
+
trackId: track.trackId,
|
|
539
|
+
sfuStreamId: track.sfuStreamId,
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
outboundAudioTrack.update(track, sample.timestamp);
|
|
543
|
+
} catch (err) {
|
|
544
|
+
logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
|
|
684
545
|
}
|
|
546
|
+
|
|
547
|
+
}
|
|
685
548
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
549
|
+
for (const track of sample.outboundVideoTracks ?? []) {
|
|
550
|
+
if (!track.peerConnectionId || !track.trackId) {
|
|
551
|
+
logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
|
|
689
552
|
|
|
690
|
-
|
|
691
|
-
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
692
555
|
|
|
693
|
-
|
|
694
|
-
|
|
556
|
+
try {
|
|
557
|
+
const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
|
|
695
558
|
|
|
696
|
-
|
|
559
|
+
if (!peerConnection) continue;
|
|
697
560
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
561
|
+
const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? peerConnection.createOutboundVideoTrack({
|
|
562
|
+
trackId: track.trackId,
|
|
563
|
+
sfuStreamId: track.sfuStreamId,
|
|
564
|
+
});
|
|
702
565
|
|
|
703
|
-
|
|
566
|
+
outboundVideoTrack.update(track, sample.timestamp);
|
|
704
567
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
}
|
|
568
|
+
} catch (err) {
|
|
569
|
+
logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
|
|
708
570
|
}
|
|
571
|
+
}
|
|
709
572
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
if (!peerConnection) {
|
|
718
|
-
logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
|
|
719
|
-
continue;
|
|
720
|
-
}
|
|
573
|
+
for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
|
|
574
|
+
if (!iceLocalCandidate.peerConnectionId) {
|
|
575
|
+
logger.warn(`Local ice candidate without peerConnectionId: ${JSON.stringify(iceLocalCandidate)}`);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
const peerConnection = this._peerConnections.get(iceLocalCandidate.peerConnectionId);
|
|
721
579
|
|
|
722
|
-
|
|
580
|
+
if (!peerConnection) {
|
|
581
|
+
logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
|
|
582
|
+
continue;
|
|
723
583
|
}
|
|
724
|
-
|
|
725
|
-
for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
|
|
726
|
-
if (!iceRemoteCandidate.peerConnectionId) {
|
|
727
|
-
logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
|
|
728
|
-
continue;
|
|
729
|
-
}
|
|
730
|
-
const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
|
|
731
584
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
585
|
+
peerConnection.ICE.addLocalCandidate(iceLocalCandidate);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
|
|
589
|
+
if (!iceRemoteCandidate.peerConnectionId) {
|
|
590
|
+
logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
|
|
591
|
+
continue;
|
|
592
|
+
}
|
|
593
|
+
const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
|
|
736
594
|
|
|
737
|
-
|
|
595
|
+
if (!peerConnection) {
|
|
596
|
+
logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
|
|
597
|
+
continue;
|
|
738
598
|
}
|
|
739
599
|
|
|
740
|
-
|
|
741
|
-
|
|
600
|
+
peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate);
|
|
601
|
+
}
|
|
742
602
|
|
|
743
|
-
|
|
744
|
-
|
|
603
|
+
for (const candidatePair of sample.iceCandidatePairs ?? []) {
|
|
604
|
+
const peerConnection = this._peerConnections.get(candidatePair.peerConnectionId);
|
|
745
605
|
|
|
746
|
-
|
|
747
|
-
}
|
|
606
|
+
if (!peerConnection) {
|
|
607
|
+
logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
|
|
748
608
|
|
|
749
|
-
|
|
609
|
+
continue;
|
|
750
610
|
}
|
|
751
611
|
|
|
752
|
-
|
|
753
|
-
|
|
612
|
+
peerConnection.ICE.update(candidatePair, sample.timestamp);
|
|
613
|
+
}
|
|
754
614
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
logger.debug(`Closing peer connection ${peerConnection.peerConnectionId} due to inactivity`);
|
|
758
|
-
peerConnection.close();
|
|
615
|
+
// close entries that are idle for too long
|
|
616
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs && this._updated < sample.timestamp) {
|
|
759
617
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
618
|
+
for (const peerConnection of this._peerConnections.values()) {
|
|
619
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - peerConnection.updated) {
|
|
620
|
+
logger.debug(`Closing peer connection ${peerConnection.peerConnectionId} due to inactivity`);
|
|
621
|
+
peerConnection.close();
|
|
622
|
+
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
for (const track of peerConnection.inboundAudioTracks.values()) {
|
|
626
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
|
|
627
|
+
logger.debug(`Closing inbound audio track ${track.trackId} due to inactivity`);
|
|
628
|
+
track.close();
|
|
767
629
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
630
|
+
}
|
|
631
|
+
for (const track of peerConnection.inboundVideoTracks.values()) {
|
|
632
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
|
|
633
|
+
logger.debug(`Closing inbound video track ${track.trackId} due to inactivity`);
|
|
634
|
+
track.close();
|
|
773
635
|
}
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
636
|
+
}
|
|
637
|
+
for (const track of peerConnection.outboundAudioTracks.values()) {
|
|
638
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < sample.timestamp - track.updated) {
|
|
639
|
+
logger.debug(`Closing outbound audio track ${track.trackId} due to inactivity`);
|
|
640
|
+
track.close();
|
|
779
641
|
}
|
|
780
642
|
}
|
|
781
643
|
}
|
|
644
|
+
}
|
|
782
645
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
646
|
+
// update metrics
|
|
647
|
+
const wasUsingTURN = this.usingTURN;
|
|
648
|
+
|
|
649
|
+
this.usingTURN = false;
|
|
650
|
+
this.availableIncomingBitrate = 0;
|
|
651
|
+
this.availableOutgoingBitrate = 0;
|
|
652
|
+
this.totalSentBytes = 0;
|
|
653
|
+
this.totalReceivedBytes = 0;
|
|
654
|
+
this.totalOutboundPacketsSent = 0;
|
|
655
|
+
this.totalInboundPacketsReceived = 0;
|
|
656
|
+
this.totalInboundPacketsLost = 0;
|
|
657
|
+
this.totalDataChannelBytesSent = 0;
|
|
658
|
+
this.totalDataChannelBytesReceived = 0;
|
|
659
|
+
this.sendingBitrate = 0;
|
|
660
|
+
this.receivingBitrate = 0;
|
|
661
|
+
let sumRttInMs = 0;
|
|
662
|
+
|
|
663
|
+
for (const peerConnection of this._peerConnections.values()) {
|
|
664
|
+
if (peerConnection.closed) continue;
|
|
665
|
+
peerConnection.updateMetrics();
|
|
666
|
+
this.totalSentBytes += peerConnection.totalSentAudioBytes + peerConnection.totalSentVideoBytes;
|
|
667
|
+
this.totalReceivedBytes += peerConnection.totalReceivedAudioBytes + peerConnection.totalReceivedVideoBytes;
|
|
668
|
+
this.totalOutboundPacketsSent += peerConnection.totalOutboundPacketsSent;
|
|
669
|
+
this.totalInboundPacketsReceived += peerConnection.totalInboundPacketsReceived;
|
|
670
|
+
this.totalInboundPacketsLost += peerConnection.totalInboundPacketsLost;
|
|
671
|
+
this.totalDataChannelBytesSent += peerConnection.totalDataChannelBytesSent;
|
|
672
|
+
this.totalDataChannelBytesReceived += peerConnection.totalDataChannelBytesReceived;
|
|
673
|
+
this.sendingBitrate += peerConnection.sendingAudioBitrate + peerConnection.sendingVideoBitrate;
|
|
674
|
+
this.receivingBitrate += peerConnection.receivingAudioBitrate + peerConnection.receivingVideoBitrate;
|
|
675
|
+
this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
|
|
676
|
+
this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
|
|
677
|
+
sumRttInMs += peerConnection.avgRttInMs ?? 0;
|
|
678
|
+
|
|
679
|
+
if (peerConnection.usingTURN) this.usingTURN = true;
|
|
680
|
+
}
|
|
818
681
|
|
|
819
|
-
|
|
682
|
+
this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
|
|
820
683
|
|
|
821
|
-
|
|
822
|
-
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
684
|
+
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
823
685
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}).finally(() => {
|
|
827
|
-
--this._processingSample;
|
|
828
|
-
});
|
|
686
|
+
this._updated = Date.now();
|
|
687
|
+
this.emit('update');
|
|
829
688
|
}
|
|
830
689
|
|
|
831
|
-
private
|
|
832
|
-
const result =
|
|
690
|
+
private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
|
|
691
|
+
const result = new ObservedPeerConnection({
|
|
833
692
|
peerConnectionId,
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
const pendingTracksTimestamp = this.ωpendingCreatedTracksTimestamp.get(peerConnectionId);
|
|
837
|
-
|
|
838
|
-
if (pendingTracksTimestamp) {
|
|
839
|
-
result.created = pendingTracksTimestamp;
|
|
840
|
-
this.ωpendingCreatedTracksTimestamp.delete(peerConnectionId);
|
|
841
|
-
}
|
|
693
|
+
label,
|
|
694
|
+
}, this);
|
|
842
695
|
|
|
843
696
|
const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }: { localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate }) => {
|
|
844
697
|
this.emit('selectedcandidatepair', {
|
|
@@ -851,25 +704,15 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
851
704
|
result.once('close', () => {
|
|
852
705
|
result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
|
|
853
706
|
this._peerConnections.delete(peerConnectionId);
|
|
854
|
-
this._model.peerConnectionIds = this._model.peerConnectionIds.filter((id) => id !== peerConnectionId);
|
|
855
|
-
this._save().catch(() => void 0);
|
|
856
707
|
});
|
|
857
708
|
result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
|
|
858
709
|
this._peerConnections.set(peerConnectionId, result);
|
|
859
|
-
this._model.peerConnectionIds.push(peerConnectionId);
|
|
860
|
-
await this._save();
|
|
861
710
|
|
|
862
711
|
this.emit('newpeerconnection', result);
|
|
863
712
|
|
|
864
713
|
return result;
|
|
865
714
|
}
|
|
866
715
|
|
|
867
|
-
private async _save() {
|
|
868
|
-
if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
|
|
869
|
-
|
|
870
|
-
return this._storageProvider.clientStorage.set(this.clientId, this._model);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
716
|
private _addClientLeftReport() {
|
|
874
717
|
if (this._left) return;
|
|
875
718
|
this._left = Date.now();
|
|
@@ -880,7 +723,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
880
723
|
this.roomId,
|
|
881
724
|
this.callId,
|
|
882
725
|
this.clientId,
|
|
883
|
-
this.
|
|
726
|
+
this._left,
|
|
884
727
|
this.userId,
|
|
885
728
|
this.marker,
|
|
886
729
|
));
|