@observertc/observer-js 0.40.0-beta → 0.40.2-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 +1 -0
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +3 -2
- package/lib/ObservedClient.d.ts +0 -5
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +35 -11
- package/lib/ObservedDataChannel.d.ts +68 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -0
- package/lib/ObservedDataChannel.js +111 -0
- package/lib/ObservedICE.d.ts.map +1 -1
- package/lib/ObservedICE.js +1 -0
- package/lib/ObservedInboundTrack.d.ts +0 -1
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +4 -5
- package/lib/ObservedOutboundTrack.d.ts +0 -1
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +4 -5
- package/lib/ObservedPeerConnection.d.ts +4 -0
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +24 -0
- package/lib/ObservedSfu.d.ts.map +1 -1
- package/lib/ObservedSfu.js +1 -0
- package/lib/Observer.d.ts +2 -0
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +8 -1
- package/package.json +1 -1
- package/src/ObservedCall.ts +4 -3
- package/src/ObservedClient.ts +34 -11
- package/src/ObservedDataChannel.ts +187 -0
- package/src/ObservedICE.ts +2 -1
- package/src/ObservedInboundTrack.ts +5 -7
- package/src/ObservedOutboundTrack.ts +5 -7
- package/src/ObservedPeerConnection.ts +30 -0
- package/src/ObservedSfu.ts +1 -0
- package/src/Observer.ts +13 -1
|
@@ -5,6 +5,7 @@ const events_1 = require("events");
|
|
|
5
5
|
const ObservedInboundTrack_1 = require("./ObservedInboundTrack");
|
|
6
6
|
const ObservedOutboundTrack_1 = require("./ObservedOutboundTrack");
|
|
7
7
|
const ObservedICE_1 = require("./ObservedICE");
|
|
8
|
+
const ObservedDataChannel_1 = require("./ObservedDataChannel");
|
|
8
9
|
class ObservedPeerConnection extends events_1.EventEmitter {
|
|
9
10
|
constructor(_model, client) {
|
|
10
11
|
super();
|
|
@@ -48,6 +49,8 @@ class ObservedPeerConnection extends events_1.EventEmitter {
|
|
|
48
49
|
this._inboundVideoTracks = new Map();
|
|
49
50
|
this._outboundAudioTracks = new Map();
|
|
50
51
|
this._outboundVideoTracks = new Map();
|
|
52
|
+
this._dataChannels = new Map();
|
|
53
|
+
this.setMaxListeners(Infinity);
|
|
51
54
|
}
|
|
52
55
|
get serviceId() {
|
|
53
56
|
return this.client.serviceId;
|
|
@@ -107,6 +110,9 @@ class ObservedPeerConnection extends events_1.EventEmitter {
|
|
|
107
110
|
get outboundVideoTracks() {
|
|
108
111
|
return this._outboundVideoTracks;
|
|
109
112
|
}
|
|
113
|
+
get dataChannels() {
|
|
114
|
+
return this._dataChannels;
|
|
115
|
+
}
|
|
110
116
|
get uptimeInMs() {
|
|
111
117
|
return this._updated - this.created;
|
|
112
118
|
}
|
|
@@ -210,6 +216,12 @@ class ObservedPeerConnection extends events_1.EventEmitter {
|
|
|
210
216
|
this.totalSentVideoPackets += track.totalSentPackets;
|
|
211
217
|
sumRttInMs = ((_a = track.rttInMs) !== null && _a !== void 0 ? _a : 0);
|
|
212
218
|
});
|
|
219
|
+
this._dataChannels.forEach((channel) => {
|
|
220
|
+
this.deltaDataChannelBytesSent += channel.deltaBytesSent;
|
|
221
|
+
this.deltaDataChannelBytesReceived += channel.deltaBytesReceived;
|
|
222
|
+
this.totalDataChannelBytesSent += channel.totalBytesSent;
|
|
223
|
+
this.totalDataChannelBytesReceived += channel.totalBytesReceived;
|
|
224
|
+
});
|
|
213
225
|
const iceRttInMs = (_a = this.ICE.stats) === null || _a === void 0 ? void 0 : _a.currentRoundTripTime;
|
|
214
226
|
let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
|
|
215
227
|
if (iceRttInMs) {
|
|
@@ -276,5 +288,17 @@ class ObservedPeerConnection extends events_1.EventEmitter {
|
|
|
276
288
|
this.emit('newoutboundvideotrack', result);
|
|
277
289
|
return result;
|
|
278
290
|
}
|
|
291
|
+
createDataChannel(channelId) {
|
|
292
|
+
if (this._closed)
|
|
293
|
+
throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
294
|
+
const result = new ObservedDataChannel_1.ObservedDataChannel({
|
|
295
|
+
channelId,
|
|
296
|
+
}, this);
|
|
297
|
+
result.on('close', () => {
|
|
298
|
+
this._dataChannels.delete(result.channelId);
|
|
299
|
+
});
|
|
300
|
+
this._dataChannels.set(result.channelId, result);
|
|
301
|
+
return result;
|
|
302
|
+
}
|
|
279
303
|
}
|
|
280
304
|
exports.ObservedPeerConnection = ObservedPeerConnection;
|
package/lib/ObservedSfu.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObservedSfu.d.ts","sourceRoot":"","sources":["../src/ObservedSfu.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAE;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,EAAE,CAAC;IACX,KAAK,EAAE,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,WAAW;IACnC,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACzG,GAAG,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CAC1F;AAED,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,YAAY;IAO9G,OAAO,CAAC,QAAQ,CAAC,MAAM;aACP,QAAQ,EAAE,QAAQ;aAClB,OAAO,EAAE,OAAO;IARjC,SAAgB,OAAO,SAAc;IAErC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAS;gBAGN,MAAM,EAAE,gBAAgB,EACzB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO;
|
|
1
|
+
{"version":3,"file":"ObservedSfu.d.ts","sourceRoot":"","sources":["../src/ObservedSfu.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAE1D,MAAM,MAAM,gBAAgB,GAAE;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,EAAE,CAAC;IACX,KAAK,EAAE,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,WAAW;IACnC,EAAE,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACzG,GAAG,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3G,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CAC1F;AAED,qBAAa,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAE,SAAQ,YAAY;IAO9G,OAAO,CAAC,QAAQ,CAAC,MAAM;aACP,QAAQ,EAAE,QAAQ;aAClB,OAAO,EAAE,OAAO;IARjC,SAAgB,OAAO,SAAc;IAErC,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAS;gBAGN,MAAM,EAAE,gBAAgB,EACzB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO;IAMjC,IAAW,SAAS,WAGnB;IAED,IAAW,KAAK,WAGf;IAED,IAAW,MAAM,WAGhB;IAED,IAAW,OAAO,WAEjB;IAED,IAAW,MAAM,YAEhB;IAEM,KAAK;IAML,MAAM,CAAC,MAAM,EAAE,SAAS;CAO/B"}
|
package/lib/ObservedSfu.js
CHANGED
|
@@ -11,6 +11,7 @@ class ObservedSfu extends events_1.EventEmitter {
|
|
|
11
11
|
this.created = Date.now();
|
|
12
12
|
this._updated = Date.now();
|
|
13
13
|
this._closed = false;
|
|
14
|
+
this.setMaxListeners(Infinity);
|
|
14
15
|
}
|
|
15
16
|
get serviceId() {
|
|
16
17
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
package/lib/Observer.d.ts
CHANGED
|
@@ -3,8 +3,10 @@ import { ObservedCall, ObservedCallModel } from './ObservedCall';
|
|
|
3
3
|
import { ReportsCollector } from './ReportsCollector';
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
import { PartialBy } from './common/utils';
|
|
6
|
+
import { ObserverSinkContext } from './common/types';
|
|
6
7
|
export type ObserverEvents = {
|
|
7
8
|
'newcall': [ObservedCall];
|
|
9
|
+
'reports': [ObserverSinkContext];
|
|
8
10
|
'close': [];
|
|
9
11
|
};
|
|
10
12
|
export type ObserverConfig = {
|
package/lib/Observer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAIrD,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,CAAC,YAAY,CAAC,CAAC;IAE1B,SAAS,EAAE,CAAC,mBAAmB,CAAC,CAAC;IACjC,OAAO,EAAE,EAAE,CAAC;CACZ,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAE5B;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAE3B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3C,oBAAoB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,QAAQ;IAChC,EAAE,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACnG,GAAG,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACpG,IAAI,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACrG,IAAI,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACpF;AAED,qBAAa,QAAS,SAAQ,YAAY;aAwBxB,MAAM,EAAE,cAAc;WAvBzB,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,QAAQ;IAkBvE,SAAgB,OAAO,mBAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,YAAY,CAAC,CAAgC;IACrD,OAAO,CAAC,OAAO,CAAS;gBAEP,MAAM,EAAE,cAAc;IAyBhC,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpF,MAAM,EAAE,SAAS,CAAC,iBAAiB,EAAE,WAAW,GAAG,SAAS,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC,CAAA;KAAE,GAC5E,YAAY,CAAC,CAAC,CAAC;IAsClB,IAAW,aAAa,IAAI,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAE5D;IAED,IAAW,MAAM,YAEhB;IAEM,KAAK;IAWZ,OAAO,CAAC,YAAY;CAepB"}
|
package/lib/Observer.js
CHANGED
|
@@ -38,7 +38,9 @@ class Observer extends events_1.EventEmitter {
|
|
|
38
38
|
this.reports = new ReportsCollector_1.ReportsCollector();
|
|
39
39
|
this._observedCalls = new Map();
|
|
40
40
|
this._closed = false;
|
|
41
|
+
this.setMaxListeners(Infinity);
|
|
41
42
|
logger.debug('Observer is created with config', this.config);
|
|
43
|
+
const onReports = (context) => this.emit('reports', context);
|
|
42
44
|
const onNewReport = (collectedReports) => {
|
|
43
45
|
if (!this.config.maxReports || this._closed)
|
|
44
46
|
return;
|
|
@@ -47,8 +49,12 @@ class Observer extends events_1.EventEmitter {
|
|
|
47
49
|
}
|
|
48
50
|
};
|
|
49
51
|
this._emitReports();
|
|
50
|
-
this.once('close', () =>
|
|
52
|
+
this.once('close', () => {
|
|
53
|
+
this.reports.off('newreport', onNewReport);
|
|
54
|
+
this.reports.off('reports', onReports);
|
|
55
|
+
});
|
|
51
56
|
this.reports.on('newreport', onNewReport);
|
|
57
|
+
this.reports.on('reports', onReports);
|
|
52
58
|
}
|
|
53
59
|
createObservedCall(config) {
|
|
54
60
|
if (this._closed) {
|
|
@@ -80,6 +86,7 @@ class Observer extends events_1.EventEmitter {
|
|
|
80
86
|
return logger.debug('Attempted to close twice');
|
|
81
87
|
}
|
|
82
88
|
this._closed = true;
|
|
89
|
+
this._observedCalls.forEach((call) => call.close());
|
|
83
90
|
this.emit('close');
|
|
84
91
|
}
|
|
85
92
|
_emitReports() {
|
package/package.json
CHANGED
package/src/ObservedCall.ts
CHANGED
|
@@ -38,6 +38,7 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
38
38
|
public readonly appData: AppData,
|
|
39
39
|
) {
|
|
40
40
|
super();
|
|
41
|
+
this.setMaxListeners(Infinity);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
public get serviceId(): string {
|
|
@@ -85,10 +86,10 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
85
86
|
this.emit('close');
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
public createClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(config: ObservedClientModel & { appData: ClientAppData, generateClientJoinedReport?: boolean }) {
|
|
89
|
+
public createClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(config: ObservedClientModel & { appData: ClientAppData, generateClientJoinedReport?: boolean, joined?: number }) {
|
|
89
90
|
if (this._closed) throw new Error(`Call ${this.callId} is closed`);
|
|
90
91
|
|
|
91
|
-
const { appData, generateClientJoinedReport, ...model } = config;
|
|
92
|
+
const { appData, generateClientJoinedReport, joined = Date.now(), ...model } = config;
|
|
92
93
|
|
|
93
94
|
const result = new ObservedClient(model, this, appData);
|
|
94
95
|
|
|
@@ -104,7 +105,7 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
104
105
|
this.roomId,
|
|
105
106
|
this.callId,
|
|
106
107
|
result.clientId,
|
|
107
|
-
|
|
108
|
+
joined,
|
|
108
109
|
result.userId,
|
|
109
110
|
result.marker,
|
|
110
111
|
));
|
package/src/ObservedClient.ts
CHANGED
|
@@ -14,18 +14,12 @@ const logger = createLogger('ObservedClient');
|
|
|
14
14
|
export type ObservedClientModel= {
|
|
15
15
|
clientId: string;
|
|
16
16
|
mediaUnitId: string;
|
|
17
|
-
overflowingProcessingThreshold?: number;
|
|
18
17
|
userId?: string,
|
|
19
18
|
marker?: string,
|
|
20
19
|
operationSystem?: OperationSystem,
|
|
21
20
|
engine?: Engine,
|
|
22
21
|
platform?: Platform,
|
|
23
22
|
browser?: Browser,
|
|
24
|
-
|
|
25
|
-
/**
|
|
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
|
|
27
|
-
*/
|
|
28
|
-
addJoinAndDetachClientEvent?: boolean;
|
|
29
23
|
};
|
|
30
24
|
|
|
31
25
|
export type ObservedClientEvents = {
|
|
@@ -101,6 +95,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
101
95
|
public readonly appData: AppData
|
|
102
96
|
) {
|
|
103
97
|
super();
|
|
98
|
+
this.setMaxListeners(Infinity);
|
|
104
99
|
}
|
|
105
100
|
|
|
106
101
|
public get clientId(): string {
|
|
@@ -194,6 +189,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
194
189
|
if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
|
|
195
190
|
throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
|
|
196
191
|
}
|
|
192
|
+
const now = Date.now();
|
|
193
|
+
|
|
197
194
|
++this._acceptedSample;
|
|
198
195
|
|
|
199
196
|
for (const peerConnection of this._peerConnections.values()) {
|
|
@@ -612,34 +609,60 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
612
609
|
peerConnection.ICE.update(candidatePair, sample.timestamp);
|
|
613
610
|
}
|
|
614
611
|
|
|
612
|
+
for (const dataChannel of sample.dataChannels ?? []) {
|
|
613
|
+
if (!dataChannel.peerConnectionId || !dataChannel.dataChannelIdentifier) {
|
|
614
|
+
logger.warn(`DataChannel without peerConnectionId or dataChannelIdentifier: ${JSON.stringify(dataChannel)}`);
|
|
615
|
+
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
try {
|
|
620
|
+
const peerConnection = this._peerConnections.get(dataChannel.peerConnectionId) ?? this._createPeerConnection(dataChannel.peerConnectionId);
|
|
621
|
+
|
|
622
|
+
if (!peerConnection) continue;
|
|
623
|
+
|
|
624
|
+
const observedDataChannel = peerConnection.dataChannels.get(dataChannel.dataChannelIdentifier) ?? peerConnection.createDataChannel(dataChannel.dataChannelIdentifier);
|
|
625
|
+
|
|
626
|
+
observedDataChannel.update(dataChannel, sample.timestamp);
|
|
627
|
+
} catch (err) {
|
|
628
|
+
logger.error(`Error creating data channel: ${(err as Error)?.message}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
615
632
|
// close entries that are idle for too long
|
|
616
633
|
if (this.call.observer.config.maxEntryIdleTimeInMs && this._updated < sample.timestamp) {
|
|
617
634
|
|
|
618
635
|
for (const peerConnection of this._peerConnections.values()) {
|
|
619
|
-
if (this.call.observer.config.maxEntryIdleTimeInMs <
|
|
636
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < peerConnection.created - peerConnection.updated) {
|
|
620
637
|
logger.debug(`Closing peer connection ${peerConnection.peerConnectionId} due to inactivity`);
|
|
621
638
|
peerConnection.close();
|
|
622
639
|
|
|
623
640
|
continue;
|
|
624
641
|
}
|
|
625
642
|
for (const track of peerConnection.inboundAudioTracks.values()) {
|
|
626
|
-
if (this.call.observer.config.maxEntryIdleTimeInMs <
|
|
643
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < track.created - track.updated) {
|
|
627
644
|
logger.debug(`Closing inbound audio track ${track.trackId} due to inactivity`);
|
|
628
645
|
track.close();
|
|
629
646
|
}
|
|
630
647
|
}
|
|
631
648
|
for (const track of peerConnection.inboundVideoTracks.values()) {
|
|
632
|
-
if (this.call.observer.config.maxEntryIdleTimeInMs <
|
|
649
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < track.created - track.updated) {
|
|
633
650
|
logger.debug(`Closing inbound video track ${track.trackId} due to inactivity`);
|
|
634
651
|
track.close();
|
|
635
652
|
}
|
|
636
653
|
}
|
|
637
654
|
for (const track of peerConnection.outboundAudioTracks.values()) {
|
|
638
|
-
if (this.call.observer.config.maxEntryIdleTimeInMs <
|
|
655
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < track.created - track.updated) {
|
|
639
656
|
logger.debug(`Closing outbound audio track ${track.trackId} due to inactivity`);
|
|
640
657
|
track.close();
|
|
641
658
|
}
|
|
642
659
|
}
|
|
660
|
+
for (const dataChannel of peerConnection.dataChannels.values()) {
|
|
661
|
+
if (this.call.observer.config.maxEntryIdleTimeInMs < dataChannel.created - dataChannel.updated) {
|
|
662
|
+
logger.debug(`Closing DataChannel ${dataChannel.channelId} due to inactivity`);
|
|
663
|
+
dataChannel.close();
|
|
664
|
+
}
|
|
665
|
+
}
|
|
643
666
|
}
|
|
644
667
|
}
|
|
645
668
|
|
|
@@ -683,7 +706,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
683
706
|
|
|
684
707
|
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
685
708
|
|
|
686
|
-
this._updated =
|
|
709
|
+
this._updated = now;
|
|
687
710
|
this.emit('update');
|
|
688
711
|
}
|
|
689
712
|
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ObservedPeerConnection } from './ObservedPeerConnection';
|
|
3
|
+
import { DataChannel } from '@observertc/sample-schemas-js';
|
|
4
|
+
import { ClientDataChannelReport } from '@observertc/report-schemas-js';
|
|
5
|
+
|
|
6
|
+
export type ObservedDataChannelState = 'connecting' | 'open' | 'closing' | 'closed';
|
|
7
|
+
|
|
8
|
+
export type ObservedDataChannelModel = {
|
|
9
|
+
channelId: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ObservedDataChannelEvents = {
|
|
13
|
+
update: [],
|
|
14
|
+
close: [],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ObservedInboundTrackStats = {
|
|
18
|
+
ssrc: number;
|
|
19
|
+
bitrate: number;
|
|
20
|
+
fractionLost: number;
|
|
21
|
+
rttInMs?: number;
|
|
22
|
+
lostPackets?: number;
|
|
23
|
+
receivedPackets?: number;
|
|
24
|
+
receivedFrames?: number;
|
|
25
|
+
decodedFrames?: number;
|
|
26
|
+
droppedFrames?: number;
|
|
27
|
+
receivedSamples?: number;
|
|
28
|
+
silentConcealedSamples?: number;
|
|
29
|
+
fractionLoss?: number;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// {
|
|
33
|
+
// [Property in keyof ObservedInboundTrackStats<K>]: ObservedInboundTrackStats<K>[Property];
|
|
34
|
+
// }
|
|
35
|
+
|
|
36
|
+
export declare interface ObservedDataChannel {
|
|
37
|
+
on<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
38
|
+
off<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
39
|
+
once<U extends keyof ObservedDataChannelEvents>(event: U, listener: (...args: ObservedDataChannelEvents[U]) => void): this;
|
|
40
|
+
emit<U extends keyof ObservedDataChannelEvents>(event: U, ...args: ObservedDataChannelEvents[U]): boolean;
|
|
41
|
+
update(sample: DataChannel, timestamp: number): void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ObservedDataChannel extends EventEmitter {
|
|
45
|
+
public readonly created = Date.now();
|
|
46
|
+
|
|
47
|
+
private _stats?: DataChannel;
|
|
48
|
+
|
|
49
|
+
private _closed = false;
|
|
50
|
+
private _updated = Date.now();
|
|
51
|
+
public bitrate = 0;
|
|
52
|
+
|
|
53
|
+
public totalReceivedMessages = 0;
|
|
54
|
+
public totalSentMessages = 0;
|
|
55
|
+
public totalBytesReceived = 0;
|
|
56
|
+
public totalBytesSent = 0;
|
|
57
|
+
|
|
58
|
+
public deltaReceivedMessages = 0;
|
|
59
|
+
public deltaSentMessages = 0;
|
|
60
|
+
public deltaBytesReceived = 0;
|
|
61
|
+
public deltaBytesSent = 0;
|
|
62
|
+
|
|
63
|
+
public constructor(
|
|
64
|
+
private readonly _model: ObservedDataChannelModel,
|
|
65
|
+
public readonly peerConnection: ObservedPeerConnection,
|
|
66
|
+
) {
|
|
67
|
+
super();
|
|
68
|
+
this.setMaxListeners(Infinity);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public get serviceId() {
|
|
72
|
+
return this.peerConnection.serviceId;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public get roomId() {
|
|
76
|
+
return this.peerConnection.roomId;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public get callId() {
|
|
80
|
+
return this.peerConnection.callId;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public get clientId() {
|
|
84
|
+
return this.peerConnection.clientId;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public get mediaUnitId() {
|
|
88
|
+
return this.peerConnection.mediaUnitId;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public get peerConnectionId() {
|
|
92
|
+
return this.peerConnection.peerConnectionId;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public get channelId() {
|
|
96
|
+
return this._model.channelId;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public get updated() {
|
|
100
|
+
return this._updated;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public get state(): ObservedDataChannelState | undefined {
|
|
104
|
+
return this._stats?.state as ObservedDataChannelState | undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public get label() {
|
|
108
|
+
return this._stats?.label;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public get protocol() {
|
|
112
|
+
return this._stats?.protocol;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public get reports() {
|
|
116
|
+
return this.peerConnection.reports;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public get stats() {
|
|
120
|
+
return this._stats;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public get closed() {
|
|
124
|
+
return this._closed;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public close() {
|
|
128
|
+
if (this._closed) return;
|
|
129
|
+
|
|
130
|
+
this._closed = true;
|
|
131
|
+
|
|
132
|
+
this.emit('close');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public resetMetrics() {
|
|
136
|
+
this.bitrate = 0;
|
|
137
|
+
this.totalReceivedMessages = 0;
|
|
138
|
+
this.totalSentMessages = 0;
|
|
139
|
+
this.totalBytesReceived = 0;
|
|
140
|
+
this.totalBytesSent = 0;
|
|
141
|
+
this.deltaReceivedMessages = 0;
|
|
142
|
+
this.deltaSentMessages = 0;
|
|
143
|
+
this.deltaBytesReceived = 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public update(sample: DataChannel, timestamp: number) {
|
|
147
|
+
if (this._closed) return;
|
|
148
|
+
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
|
|
151
|
+
const report: ClientDataChannelReport = {
|
|
152
|
+
serviceId: this.peerConnection.client.call.serviceId,
|
|
153
|
+
roomId: this.peerConnection.client.call.roomId,
|
|
154
|
+
callId: this.peerConnection.client.call.callId,
|
|
155
|
+
clientId: this.peerConnection.client.clientId,
|
|
156
|
+
userId: this.peerConnection.client.userId,
|
|
157
|
+
mediaUnitId: this.peerConnection.client.mediaUnitId,
|
|
158
|
+
...sample,
|
|
159
|
+
timestamp,
|
|
160
|
+
sampleSeq: -1,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
this.reports.addClientDataChannelReport(report);
|
|
164
|
+
|
|
165
|
+
sample.bytesReceived;
|
|
166
|
+
sample.bytesSent;
|
|
167
|
+
sample.messageReceived;
|
|
168
|
+
sample.messageSent;
|
|
169
|
+
|
|
170
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
171
|
+
|
|
172
|
+
this.bitrate = ((sample.bytesReceived ?? 0) - (this._stats?.bytesReceived ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
173
|
+
this.deltaSentMessages = (sample.messageSent ?? 0) - (this._stats?.messageSent ?? 0);
|
|
174
|
+
this.deltaReceivedMessages = (sample.messageReceived ?? 0) - (this._stats?.messageReceived ?? 0);
|
|
175
|
+
this.deltaBytesSent = (sample.bytesSent ?? 0) - (this._stats?.bytesSent ?? 0);
|
|
176
|
+
this.deltaBytesReceived = (sample.bytesReceived ?? 0) - (this._stats?.bytesReceived ?? 0);
|
|
177
|
+
|
|
178
|
+
this.totalBytesReceived = sample.bytesReceived ?? 0;
|
|
179
|
+
this.totalBytesSent = sample.bytesSent ?? 0;
|
|
180
|
+
this.totalReceivedMessages = sample.messageReceived ?? 0;
|
|
181
|
+
this.totalSentMessages = sample.messageSent ?? 0;
|
|
182
|
+
|
|
183
|
+
this._stats = sample;
|
|
184
|
+
this._updated = timestamp;
|
|
185
|
+
this.emit('update');
|
|
186
|
+
}
|
|
187
|
+
}
|
package/src/ObservedICE.ts
CHANGED
|
@@ -40,6 +40,7 @@ export class ObservedICE extends EventEmitter {
|
|
|
40
40
|
public readonly peerConnection: ObservedPeerConnection,
|
|
41
41
|
) {
|
|
42
42
|
super();
|
|
43
|
+
this.setMaxListeners(Infinity);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
public get reports() {
|
|
@@ -147,7 +148,7 @@ export class ObservedICE extends EventEmitter {
|
|
|
147
148
|
if (!candidatePair.nominated) return;
|
|
148
149
|
|
|
149
150
|
this._stats = candidatePair;
|
|
150
|
-
|
|
151
|
+
|
|
151
152
|
if (
|
|
152
153
|
candidatePair.localCandidateId &&
|
|
153
154
|
candidatePair.localCandidateId !== this._selectedLocalCandidateId &&
|
|
@@ -82,6 +82,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
82
82
|
public readonly peerConnection: ObservedPeerConnection,
|
|
83
83
|
) {
|
|
84
84
|
super();
|
|
85
|
+
this.setMaxListeners(Infinity);
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
public get serviceId() {
|
|
@@ -136,10 +137,6 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
136
137
|
return this.peerConnection.reports;
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
public get uptimeInMs() {
|
|
140
|
-
return this._updated - this.created;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
140
|
public set remoteOutboundTrack(track: ObservedOutboundTrack<Kind> | undefined) {
|
|
144
141
|
if (this._closed) return;
|
|
145
142
|
if (this._remoteOutboundTrack) return;
|
|
@@ -182,7 +179,8 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
182
179
|
|
|
183
180
|
public update(sample: ObservedInboundTrackStatsUpdate<Kind>, timestamp: number) {
|
|
184
181
|
if (this._closed) return;
|
|
185
|
-
|
|
182
|
+
|
|
183
|
+
const now = Date.now();
|
|
186
184
|
const report: InboundAudioTrackReport | InboundVideoTrackReport = {
|
|
187
185
|
serviceId: this.peerConnection.client.call.serviceId,
|
|
188
186
|
roomId: this.peerConnection.client.call.roomId,
|
|
@@ -212,7 +210,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
212
210
|
this._model.sfuSinkId = sample.sfuSinkId;
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
const elapsedTimeInMs = Math.max(1,
|
|
213
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
216
214
|
const lastStat = this._stats.get(sample.ssrc);
|
|
217
215
|
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
218
216
|
const bitrate = ((sample.bytesReceived ?? 0) - (lastStat?.bytesReceived ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
@@ -275,7 +273,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
275
273
|
this.deltaSilentConcealedSamples = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.silentConcealedSamples ?? 0), 0);
|
|
276
274
|
this.fractionLoss = 0 < this.deltaReceivedPackets && 0 < this.deltaLostPackets ? (this.deltaLostPackets / (this.deltaReceivedPackets + this.deltaLostPackets)) : 0;
|
|
277
275
|
|
|
278
|
-
this._updated =
|
|
276
|
+
this._updated = now;
|
|
279
277
|
this.emit('update');
|
|
280
278
|
}
|
|
281
279
|
}
|
|
@@ -70,6 +70,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
70
70
|
public readonly peerConnection: ObservedPeerConnection,
|
|
71
71
|
) {
|
|
72
72
|
super();
|
|
73
|
+
this.setMaxListeners(Infinity);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
public get serviceId() {
|
|
@@ -124,10 +125,6 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
124
125
|
return this._stats;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
public get uptimeInMs() {
|
|
128
|
-
return this._updated - this.created;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
128
|
public get closed() {
|
|
132
129
|
return this._closed;
|
|
133
130
|
}
|
|
@@ -152,7 +149,8 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
152
149
|
|
|
153
150
|
public update(sample: ObservedOutboundTrackStatsUpdate<Kind>, timestamp: number): void {
|
|
154
151
|
if (this._closed) return;
|
|
155
|
-
|
|
152
|
+
|
|
153
|
+
const now = Date.now();
|
|
156
154
|
const report: OutboundAudioTrackReport | OutboundVideoTrackReport = {
|
|
157
155
|
serviceId: this.peerConnection.client.serviceId,
|
|
158
156
|
roomId: this.peerConnection.client.call.roomId,
|
|
@@ -169,7 +167,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
169
167
|
if (this.kind === 'audio') this.reports.addOutboundAudioTrackReport(report);
|
|
170
168
|
else if (this.kind === 'video') this.reports.addOutboundVideoTrackReport(report);
|
|
171
169
|
|
|
172
|
-
const elapsedTimeInMs = Math.max(1,
|
|
170
|
+
const elapsedTimeInMs = Math.max(1, now - this._updated);
|
|
173
171
|
const lastStat = this._stats.get(sample.ssrc);
|
|
174
172
|
const rttInMs = sample.roundTripTime ? sample.roundTripTime * 1000 : undefined;
|
|
175
173
|
const bitrate = ((sample.bytesSent ?? 0) - (lastStat?.bytesSent ?? 0)) * 8 / (elapsedTimeInMs / 1000);
|
|
@@ -228,7 +226,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
228
226
|
else if (this.kind === 'video') this.peerConnection.client.call.sfuStreamIdToOutboundVideoTrack.set(this._model.sfuStreamId, this as ObservedOutboundTrack<'video'>);
|
|
229
227
|
}
|
|
230
228
|
|
|
231
|
-
this._updated =
|
|
229
|
+
this._updated = now;
|
|
232
230
|
this.emit('update');
|
|
233
231
|
}
|
|
234
232
|
|
|
@@ -5,6 +5,7 @@ import { ObservedInboundTrack, ObservedInboundTrackModel } from './ObservedInbou
|
|
|
5
5
|
import { ObservedOutboundTrack, ObservedOutboundTrackModel } from './ObservedOutboundTrack';
|
|
6
6
|
import { PeerConnectionTransportReport } from '@observertc/report-schemas-js';
|
|
7
7
|
import { ObservedICE } from './ObservedICE';
|
|
8
|
+
import { ObservedDataChannel } from './ObservedDataChannel';
|
|
8
9
|
|
|
9
10
|
export type ObservedPeerConnectionEvents = {
|
|
10
11
|
update: [],
|
|
@@ -77,12 +78,14 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
77
78
|
private readonly _inboundVideoTracks = new Map<string, ObservedInboundTrack<'video'>>();
|
|
78
79
|
private readonly _outboundAudioTracks = new Map<string, ObservedOutboundTrack<'audio'>>();
|
|
79
80
|
private readonly _outboundVideoTracks = new Map<string, ObservedOutboundTrack<'video'>>();
|
|
81
|
+
private readonly _dataChannels = new Map<number, ObservedDataChannel>();
|
|
80
82
|
|
|
81
83
|
public constructor(
|
|
82
84
|
private readonly _model: ObservedPeerConnectionModel,
|
|
83
85
|
public readonly client: ObservedClient,
|
|
84
86
|
) {
|
|
85
87
|
super();
|
|
88
|
+
this.setMaxListeners(Infinity);
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
public get serviceId() {
|
|
@@ -158,6 +161,10 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
158
161
|
return this._outboundVideoTracks;
|
|
159
162
|
}
|
|
160
163
|
|
|
164
|
+
public get dataChannels(): ReadonlyMap<number, ObservedDataChannel> {
|
|
165
|
+
return this._dataChannels;
|
|
166
|
+
}
|
|
167
|
+
|
|
161
168
|
public get uptimeInMs() {
|
|
162
169
|
return this._updated - this.created;
|
|
163
170
|
}
|
|
@@ -285,6 +292,14 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
285
292
|
|
|
286
293
|
sumRttInMs = (track.rttInMs ?? 0);
|
|
287
294
|
});
|
|
295
|
+
|
|
296
|
+
this._dataChannels.forEach((channel) => {
|
|
297
|
+
this.deltaDataChannelBytesSent += channel.deltaBytesSent;
|
|
298
|
+
this.deltaDataChannelBytesReceived += channel.deltaBytesReceived;
|
|
299
|
+
this.totalDataChannelBytesSent += channel.totalBytesSent;
|
|
300
|
+
this.totalDataChannelBytesReceived += channel.totalBytesReceived;
|
|
301
|
+
});
|
|
302
|
+
|
|
288
303
|
const iceRttInMs = this.ICE.stats?.currentRoundTripTime;
|
|
289
304
|
let nrOfBelongings = this._inboundAudioTracks.size + this._inboundVideoTracks.size + this._outboundAudioTracks.size + this._outboundVideoTracks.size;
|
|
290
305
|
|
|
@@ -393,4 +408,19 @@ export class ObservedPeerConnection extends EventEmitter {
|
|
|
393
408
|
|
|
394
409
|
return result;
|
|
395
410
|
}
|
|
411
|
+
|
|
412
|
+
public createDataChannel(channelId: number) {
|
|
413
|
+
if (this._closed) throw new Error(`PeerConnection ${this.peerConnectionId} is closed`);
|
|
414
|
+
|
|
415
|
+
const result = new ObservedDataChannel({
|
|
416
|
+
channelId,
|
|
417
|
+
}, this);
|
|
418
|
+
|
|
419
|
+
result.on('close', () => {
|
|
420
|
+
this._dataChannels.delete(result.channelId);
|
|
421
|
+
});
|
|
422
|
+
this._dataChannels.set(result.channelId, result);
|
|
423
|
+
|
|
424
|
+
return result;
|
|
425
|
+
}
|
|
396
426
|
}
|