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