@observertc/observer-js 0.40.3-beta → 0.40.5-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/CallSummary.d.ts +2 -9
- package/lib/CallSummary.d.ts.map +1 -1
- package/lib/ObservedCall.d.ts +2 -0
- package/lib/ObservedCall.d.ts.map +1 -1
- package/lib/ObservedCall.js +8 -0
- package/lib/ObservedClient.d.ts +20 -2
- package/lib/ObservedClient.d.ts.map +1 -1
- package/lib/ObservedClient.js +57 -18
- package/lib/ObservedDataChannel.d.ts +1 -0
- package/lib/ObservedDataChannel.d.ts.map +1 -1
- package/lib/ObservedDataChannel.js +1 -1
- package/lib/ObservedICE.d.ts +1 -0
- package/lib/ObservedICE.d.ts.map +1 -1
- package/lib/ObservedICE.js +1 -1
- package/lib/ObservedInboundTrack.d.ts +1 -0
- package/lib/ObservedInboundTrack.d.ts.map +1 -1
- package/lib/ObservedInboundTrack.js +1 -1
- package/lib/ObservedOutboundTrack.d.ts +1 -0
- package/lib/ObservedOutboundTrack.d.ts.map +1 -1
- package/lib/ObservedOutboundTrack.js +2 -1
- package/lib/ObservedPeerConnection.d.ts +6 -3
- package/lib/ObservedPeerConnection.d.ts.map +1 -1
- package/lib/ObservedPeerConnection.js +51 -42
- package/lib/ObservedSfu.d.ts +12 -0
- package/lib/ObservedSfu.d.ts.map +1 -1
- package/lib/ObservedSfu.js +76 -0
- package/lib/ObservedSfuInboundRtpPad.d.ts +38 -0
- package/lib/ObservedSfuInboundRtpPad.d.ts.map +1 -0
- package/lib/ObservedSfuInboundRtpPad.js +67 -0
- package/lib/ObservedSfuOutboundRtpPad.d.ts +38 -0
- package/lib/ObservedSfuOutboundRtpPad.d.ts.map +1 -0
- package/lib/ObservedSfuOutboundRtpPad.js +68 -0
- package/lib/ObservedSfuSctpChannel.d.ts +38 -0
- package/lib/ObservedSfuSctpChannel.d.ts.map +1 -0
- package/lib/ObservedSfuSctpChannel.js +53 -0
- package/lib/ObservedSfuTransport.d.ts +54 -0
- package/lib/ObservedSfuTransport.d.ts.map +1 -0
- package/lib/ObservedSfuTransport.js +116 -0
- package/lib/Observer.d.ts +5 -0
- package/lib/Observer.d.ts.map +1 -1
- package/lib/Observer.js +21 -0
- package/package.json +1 -1
- package/src/CallSummary.ts +2 -10
- package/src/ObservedCall.ts +9 -0
- package/src/ObservedClient.ts +71 -21
- package/src/ObservedDataChannel.ts +2 -0
- package/src/ObservedICE.ts +3 -0
- package/src/ObservedInboundTrack.ts +2 -0
- package/src/ObservedOutboundTrack.ts +3 -0
- package/src/ObservedPeerConnection.ts +56 -45
- package/src/ObservedSfu.ts +118 -2
- package/src/ObservedSfuInboundRtpPad.ts +100 -0
- package/src/ObservedSfuOutboundRtpPad.ts +101 -0
- package/src/ObservedSfuSctpChannel.ts +97 -0
- package/src/ObservedSfuTransport.ts +179 -0
- package/src/Observer.ts +31 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import { SfuTransport } from '@observertc/sample-schemas-js';
|
|
4
|
+
import { ObservedSfu } from './ObservedSfu';
|
|
5
|
+
import { ObservedSfuInboundRtpPad, ObservedSfuInboundRtpPadModel } from './ObservedSfuInboundRtpPad';
|
|
6
|
+
import { ObservedSfuOutboundRtpPad, ObservedSfuOutboundRtpPadModel } from './ObservedSfuOutboundRtpPad';
|
|
7
|
+
import { ObservedSfuSctpChannel, ObservedSfuSctpChannelModel } from './ObservedSfuSctpChannel';
|
|
8
|
+
export type ObservedSfuTransportModel = {
|
|
9
|
+
sfuTransportId: string;
|
|
10
|
+
};
|
|
11
|
+
export type ObservedSfuTransportEvents = {
|
|
12
|
+
update: [];
|
|
13
|
+
close: [];
|
|
14
|
+
newsfuoutboundrtppad: [ObservedSfuOutboundRtpPad];
|
|
15
|
+
newsfuinboundrtppad: [ObservedSfuInboundRtpPad];
|
|
16
|
+
newsfusctpchannel: [ObservedSfuSctpChannel];
|
|
17
|
+
};
|
|
18
|
+
export declare interface ObservedSfuTransport {
|
|
19
|
+
on<U extends keyof ObservedSfuTransportEvents>(event: U, listener: (...args: ObservedSfuTransportEvents[U]) => void): this;
|
|
20
|
+
off<U extends keyof ObservedSfuTransportEvents>(event: U, listener: (...args: ObservedSfuTransportEvents[U]) => void): this;
|
|
21
|
+
once<U extends keyof ObservedSfuTransportEvents>(event: U, listener: (...args: ObservedSfuTransportEvents[U]) => void): this;
|
|
22
|
+
emit<U extends keyof ObservedSfuTransportEvents>(event: U, ...args: ObservedSfuTransportEvents[U]): boolean;
|
|
23
|
+
update(sample: SfuTransport, timestamp: number): void;
|
|
24
|
+
}
|
|
25
|
+
export declare class ObservedSfuTransport extends EventEmitter {
|
|
26
|
+
private readonly _model;
|
|
27
|
+
readonly sfu: ObservedSfu;
|
|
28
|
+
readonly created: number;
|
|
29
|
+
stats?: SfuTransport;
|
|
30
|
+
private _updated;
|
|
31
|
+
private _closed;
|
|
32
|
+
private _marker?;
|
|
33
|
+
private readonly _inboundRtpPads;
|
|
34
|
+
private readonly _outboundRtpPads;
|
|
35
|
+
private readonly _sctpChannels;
|
|
36
|
+
constructor(_model: ObservedSfuTransportModel, sfu: ObservedSfu);
|
|
37
|
+
get inboundRtpPads(): ReadonlyMap<string, ObservedSfuInboundRtpPad>;
|
|
38
|
+
get outboundRtpPads(): ReadonlyMap<string, ObservedSfuOutboundRtpPad>;
|
|
39
|
+
get sctpChannels(): ReadonlyMap<string, ObservedSfuSctpChannel>;
|
|
40
|
+
get serviceId(): string;
|
|
41
|
+
get mediaUnitId(): string;
|
|
42
|
+
get sfuId(): string;
|
|
43
|
+
get sfuTransportId(): string;
|
|
44
|
+
get reports(): import("./ReportsCollector").ReportsCollector;
|
|
45
|
+
get updated(): number;
|
|
46
|
+
get marker(): string | undefined;
|
|
47
|
+
set marker(value: string | undefined);
|
|
48
|
+
get closed(): boolean;
|
|
49
|
+
close(): void;
|
|
50
|
+
createSfuOutboundRtpPad(model: ObservedSfuOutboundRtpPadModel): ObservedSfuOutboundRtpPad;
|
|
51
|
+
createSfuInboundRtpPad(model: ObservedSfuInboundRtpPadModel): ObservedSfuInboundRtpPad;
|
|
52
|
+
createSfuSctpChannel(model: ObservedSfuSctpChannelModel): ObservedSfuSctpChannel;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=ObservedSfuTransport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ObservedSfuTransport.d.ts","sourceRoot":"","sources":["../src/ObservedSfuTransport.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,wBAAwB,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AACrG,OAAO,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AACxG,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE/F,MAAM,MAAM,yBAAyB,GAAE;IACtC,cAAc,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACxC,MAAM,EAAE,EAAE,CAAC;IACX,KAAK,EAAE,EAAE,CAAC;IACV,oBAAoB,EAAE,CAAC,yBAAyB,CAAC,CAAC;IAClD,mBAAmB,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAChD,iBAAiB,EAAE,CAAC,sBAAsB,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,CAAC,OAAO,WAAW,oBAAoB;IAC5C,EAAE,CAAC,CAAC,SAAS,MAAM,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3H,GAAG,CAAC,CAAC,SAAS,MAAM,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5H,IAAI,CAAC,CAAC,SAAS,MAAM,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7H,IAAI,CAAC,CAAC,SAAS,MAAM,0BAA0B,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;IAE5G,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACtD;AAED,qBAAa,oBAAqB,SAAQ,YAAY;IAapD,OAAO,CAAC,QAAQ,CAAC,MAAM;aACP,GAAG,EAAE,WAAW;IAbjC,SAAgB,OAAO,SAAc;IAE9B,KAAK,CAAC,EAAE,YAAY,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAc;IAC9B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAS;IAEzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+C;IAC/E,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgD;IACjF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6C;gBAGzD,MAAM,EAAE,yBAAyB,EAClC,GAAG,EAAE,WAAW;IAMjC,IAAW,cAAc,IAAI,WAAW,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAEzE;IAED,IAAW,eAAe,IAAI,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAE3E;IAED,IAAW,YAAY,IAAI,WAAW,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAErE;IAED,IAAW,SAAS,WAEnB;IAED,IAAW,WAAW,WAErB;IAED,IAAW,KAAK,WAEf;IAED,IAAW,cAAc,WAExB;IAED,IAAW,OAAO,kDAEjB;IAED,IAAW,OAAO,WAEjB;IAED,IAAW,MAAM,IAIQ,MAAM,GAAG,SAAS,CAF1C;IAED,IAAW,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAK1C;IAED,IAAW,MAAM,YAEhB;IAEM,KAAK;IA+BL,uBAAuB,CAAC,KAAK,EAAE,8BAA8B;IAgB7D,sBAAsB,CAAC,KAAK,EAAE,6BAA6B;IAgB3D,oBAAoB,CAAC,KAAK,EAAE,2BAA2B;CAe9D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ObservedSfuTransport = void 0;
|
|
4
|
+
const events_1 = require("events");
|
|
5
|
+
const ObservedSfuInboundRtpPad_1 = require("./ObservedSfuInboundRtpPad");
|
|
6
|
+
const ObservedSfuOutboundRtpPad_1 = require("./ObservedSfuOutboundRtpPad");
|
|
7
|
+
const ObservedSfuSctpChannel_1 = require("./ObservedSfuSctpChannel");
|
|
8
|
+
class ObservedSfuTransport extends events_1.EventEmitter {
|
|
9
|
+
constructor(_model, sfu) {
|
|
10
|
+
super();
|
|
11
|
+
this._model = _model;
|
|
12
|
+
this.sfu = sfu;
|
|
13
|
+
this.created = Date.now();
|
|
14
|
+
this._updated = Date.now();
|
|
15
|
+
this._closed = false;
|
|
16
|
+
this._inboundRtpPads = new Map();
|
|
17
|
+
this._outboundRtpPads = new Map();
|
|
18
|
+
this._sctpChannels = new Map();
|
|
19
|
+
this.setMaxListeners(Infinity);
|
|
20
|
+
}
|
|
21
|
+
get inboundRtpPads() {
|
|
22
|
+
return this._inboundRtpPads;
|
|
23
|
+
}
|
|
24
|
+
get outboundRtpPads() {
|
|
25
|
+
return this._outboundRtpPads;
|
|
26
|
+
}
|
|
27
|
+
get sctpChannels() {
|
|
28
|
+
return this._sctpChannels;
|
|
29
|
+
}
|
|
30
|
+
get serviceId() {
|
|
31
|
+
return this.sfu.serviceId;
|
|
32
|
+
}
|
|
33
|
+
get mediaUnitId() {
|
|
34
|
+
return this.sfu.mediaUnitId;
|
|
35
|
+
}
|
|
36
|
+
get sfuId() {
|
|
37
|
+
return this.sfu.sfuId;
|
|
38
|
+
}
|
|
39
|
+
get sfuTransportId() {
|
|
40
|
+
return this._model.sfuTransportId;
|
|
41
|
+
}
|
|
42
|
+
get reports() {
|
|
43
|
+
return this.sfu.reports;
|
|
44
|
+
}
|
|
45
|
+
get updated() {
|
|
46
|
+
return this._updated;
|
|
47
|
+
}
|
|
48
|
+
get marker() {
|
|
49
|
+
return this._marker;
|
|
50
|
+
}
|
|
51
|
+
set marker(value) {
|
|
52
|
+
this._marker = value;
|
|
53
|
+
this._inboundRtpPads.forEach((pad) => (pad.marker = value));
|
|
54
|
+
this._outboundRtpPads.forEach((pad) => (pad.marker = value));
|
|
55
|
+
this._sctpChannels.forEach((channel) => (channel.marker = value));
|
|
56
|
+
}
|
|
57
|
+
get closed() {
|
|
58
|
+
return this._closed;
|
|
59
|
+
}
|
|
60
|
+
close() {
|
|
61
|
+
if (this._closed)
|
|
62
|
+
return;
|
|
63
|
+
this._closed = true;
|
|
64
|
+
[...this._inboundRtpPads.values()].forEach((pad) => pad.close());
|
|
65
|
+
[...this._outboundRtpPads.values()].forEach((pad) => pad.close());
|
|
66
|
+
[...this._sctpChannels.values()].forEach((channel) => channel.close());
|
|
67
|
+
this.emit('close');
|
|
68
|
+
}
|
|
69
|
+
update(sample, timestamp) {
|
|
70
|
+
const report = Object.assign(Object.assign({ serviceId: this.serviceId, mediaUnitId: this.mediaUnitId, sfuId: this.sfuId, callId: undefined, roomId: undefined }, sample), { timestamp, marker: this.marker });
|
|
71
|
+
this.reports.addSfuTransportReport(report);
|
|
72
|
+
this.stats = sample;
|
|
73
|
+
this._updated = Date.now();
|
|
74
|
+
this.emit('update');
|
|
75
|
+
}
|
|
76
|
+
createSfuOutboundRtpPad(model) {
|
|
77
|
+
if (this._closed)
|
|
78
|
+
throw new Error('Cannot create SfuOutboundRtpPad on closed SfuTransport');
|
|
79
|
+
if (this._inboundRtpPads.has(model.sfuOutboundRtpPadId))
|
|
80
|
+
throw new Error(`SfuOutboundRtpPad with id ${model.sfuOutboundRtpPadId} already exists`);
|
|
81
|
+
const result = new ObservedSfuOutboundRtpPad_1.ObservedSfuOutboundRtpPad(model, this);
|
|
82
|
+
result.once('close', () => {
|
|
83
|
+
this._outboundRtpPads.delete(model.sfuOutboundRtpPadId);
|
|
84
|
+
});
|
|
85
|
+
this._outboundRtpPads.set(model.sfuOutboundRtpPadId, result);
|
|
86
|
+
this.emit('newsfuoutboundrtppad', result);
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
createSfuInboundRtpPad(model) {
|
|
90
|
+
if (this._closed)
|
|
91
|
+
throw new Error('Cannot create SfuInboundRtpPad on closed SfuTransport');
|
|
92
|
+
if (this._inboundRtpPads.has(model.sfuInboundRtpPadId))
|
|
93
|
+
throw new Error(`SfuInboundRtpPad with id ${model.sfuInboundRtpPadId} already exists`);
|
|
94
|
+
const result = new ObservedSfuInboundRtpPad_1.ObservedSfuInboundRtpPad(model, this);
|
|
95
|
+
result.once('close', () => {
|
|
96
|
+
this._inboundRtpPads.delete(model.sfuInboundRtpPadId);
|
|
97
|
+
});
|
|
98
|
+
this._inboundRtpPads.set(model.sfuInboundRtpPadId, result);
|
|
99
|
+
this.emit('newsfuinboundrtppad', result);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
createSfuSctpChannel(model) {
|
|
103
|
+
if (this._closed)
|
|
104
|
+
throw new Error('Cannot create SfuSctpChannel on closed SfuTransport');
|
|
105
|
+
if (this._sctpChannels.has(model.sfuSctpChannelId))
|
|
106
|
+
throw new Error(`SfuSctpChannel with id ${model.sfuSctpChannelId} already exists`);
|
|
107
|
+
const result = new ObservedSfuSctpChannel_1.ObservedSfuSctpChannel(model, this);
|
|
108
|
+
result.once('close', () => {
|
|
109
|
+
this._sctpChannels.delete(model.sfuSctpChannelId);
|
|
110
|
+
});
|
|
111
|
+
this._sctpChannels.set(model.sfuSctpChannelId, result);
|
|
112
|
+
this.emit('newsfusctpchannel', result);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
exports.ObservedSfuTransport = ObservedSfuTransport;
|
package/lib/Observer.d.ts
CHANGED
|
@@ -4,8 +4,10 @@ import { ReportsCollector } from './ReportsCollector';
|
|
|
4
4
|
import { EventEmitter } from 'events';
|
|
5
5
|
import { PartialBy } from './common/utils';
|
|
6
6
|
import { ObserverSinkContext } from './common/types';
|
|
7
|
+
import { ObservedSfu, ObservedSfuModel } from './ObservedSfu';
|
|
7
8
|
export type ObserverEvents = {
|
|
8
9
|
'newcall': [ObservedCall];
|
|
10
|
+
'newsfu': [ObservedSfu];
|
|
9
11
|
'reports': [ObserverSinkContext];
|
|
10
12
|
'close': [];
|
|
11
13
|
};
|
|
@@ -39,13 +41,16 @@ export declare class Observer extends EventEmitter {
|
|
|
39
41
|
static create(providedConfig: Partial<ObserverConfig>): Observer;
|
|
40
42
|
readonly reports: ReportsCollector;
|
|
41
43
|
private readonly _observedCalls;
|
|
44
|
+
private readonly _observedSfus;
|
|
42
45
|
private _reportTimer?;
|
|
43
46
|
private _closed;
|
|
44
47
|
constructor(config: ObserverConfig);
|
|
45
48
|
createObservedCall<T extends Record<string, unknown> = Record<string, unknown>>(config: PartialBy<ObservedCallModel, 'serviceId' | 'started'> & {
|
|
46
49
|
appData: T;
|
|
47
50
|
}): ObservedCall<T>;
|
|
51
|
+
createObservedSfu<AppData extends Record<string, unknown> = Record<string, unknown>>(model: ObservedSfuModel, appData: AppData): ObservedSfu<AppData>;
|
|
48
52
|
get observedCalls(): ReadonlyMap<string, ObservedCall>;
|
|
53
|
+
get observedSfus(): ReadonlyMap<string, ObservedSfu>;
|
|
49
54
|
get closed(): boolean;
|
|
50
55
|
close(): void;
|
|
51
56
|
private _emitReports;
|
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;AAE3C,OAAO,EAAE,mBAAmB,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;AACrD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAI9D,MAAM,MAAM,cAAc,GAAG;IAC5B,SAAS,EAAE,CAAC,YAAY,CAAC,CAAC;IAC1B,QAAQ,EAAE,CAAC,WAAW,CAAC,CAAC;IACxB,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;aA0BxB,MAAM,EAAE,cAAc;WAzBzB,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,QAAQ;IAkBvE,SAAgB,OAAO,mBAA0B;IACjD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAmC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkC;IAEhE,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;IAsCX,iBAAiB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzF,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,OAAO,GACd,WAAW,CAAC,OAAO,CAAC;IAoBvB,IAAW,aAAa,IAAI,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAE5D;IAED,IAAW,YAAY,IAAI,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,CAE1D;IAED,IAAW,MAAM,YAEhB;IAEM,KAAK;IAWZ,OAAO,CAAC,YAAY;CAepB"}
|
package/lib/Observer.js
CHANGED
|
@@ -17,6 +17,7 @@ const ObservedCall_1 = require("./ObservedCall");
|
|
|
17
17
|
const ReportsCollector_1 = require("./ReportsCollector");
|
|
18
18
|
const events_1 = require("events");
|
|
19
19
|
const callEventReports_1 = require("./common/callEventReports");
|
|
20
|
+
const ObservedSfu_1 = require("./ObservedSfu");
|
|
20
21
|
const logger = (0, logger_1.createLogger)('Observer');
|
|
21
22
|
class Observer extends events_1.EventEmitter {
|
|
22
23
|
static create(providedConfig) {
|
|
@@ -37,6 +38,7 @@ class Observer extends events_1.EventEmitter {
|
|
|
37
38
|
this.config = config;
|
|
38
39
|
this.reports = new ReportsCollector_1.ReportsCollector();
|
|
39
40
|
this._observedCalls = new Map();
|
|
41
|
+
this._observedSfus = new Map();
|
|
40
42
|
this._closed = false;
|
|
41
43
|
this.setMaxListeners(Infinity);
|
|
42
44
|
logger.debug('Observer is created with config', this.config);
|
|
@@ -75,9 +77,28 @@ class Observer extends events_1.EventEmitter {
|
|
|
75
77
|
this.emit('newcall', call);
|
|
76
78
|
return call;
|
|
77
79
|
}
|
|
80
|
+
createObservedSfu(model, appData) {
|
|
81
|
+
if (this._closed) {
|
|
82
|
+
throw new Error('Attempted to create an sfu source on a closed observer');
|
|
83
|
+
}
|
|
84
|
+
const sfu = new ObservedSfu_1.ObservedSfu(model, this, appData);
|
|
85
|
+
if (this._closed)
|
|
86
|
+
throw new Error('Cannot create an observed sfu on a closed observer');
|
|
87
|
+
if (this._observedSfus.has(sfu.sfuId))
|
|
88
|
+
throw new Error(`Observed SFU with id ${sfu.sfuId} already exists`);
|
|
89
|
+
sfu.once('close', () => {
|
|
90
|
+
this._observedSfus.delete(sfu.sfuId);
|
|
91
|
+
});
|
|
92
|
+
this._observedSfus.set(sfu.sfuId, sfu);
|
|
93
|
+
this.emit('newsfu', sfu);
|
|
94
|
+
return sfu;
|
|
95
|
+
}
|
|
78
96
|
get observedCalls() {
|
|
79
97
|
return this._observedCalls;
|
|
80
98
|
}
|
|
99
|
+
get observedSfus() {
|
|
100
|
+
return this._observedSfus;
|
|
101
|
+
}
|
|
81
102
|
get closed() {
|
|
82
103
|
return this._closed;
|
|
83
104
|
}
|
package/package.json
CHANGED
package/src/CallSummary.ts
CHANGED
|
@@ -2,14 +2,7 @@ export interface ClientSummary {
|
|
|
2
2
|
clientId: string;
|
|
3
3
|
userId: string;
|
|
4
4
|
joined: number;
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface DetectedIssues {
|
|
9
|
-
clientId: string,
|
|
10
|
-
issue: string,
|
|
11
|
-
started: number,
|
|
12
|
-
ended: number,
|
|
5
|
+
durationInMs: number;
|
|
13
6
|
}
|
|
14
7
|
|
|
15
8
|
export interface CallSummary {
|
|
@@ -17,7 +10,6 @@ export interface CallSummary {
|
|
|
17
10
|
roomId: string;
|
|
18
11
|
callId: string;
|
|
19
12
|
started: number;
|
|
20
|
-
|
|
13
|
+
durationInMs: number;
|
|
21
14
|
clients: ClientSummary[];
|
|
22
|
-
detectedIssues: DetectedIssues[];
|
|
23
15
|
}
|
package/src/ObservedCall.ts
CHANGED
|
@@ -25,11 +25,14 @@ export declare interface ObservedCall {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
|
|
28
|
+
public readonly created = Date.now();
|
|
29
|
+
|
|
28
30
|
private readonly _clients = new Map<string, ObservedClient>();
|
|
29
31
|
|
|
30
32
|
public readonly sfuStreamIdToOutboundAudioTrack = new Map<string | number, ObservedOutboundTrack<'audio'>>();
|
|
31
33
|
public readonly sfuStreamIdToOutboundVideoTrack = new Map<string | number, ObservedOutboundTrack<'video'>>();
|
|
32
34
|
private _closed = false;
|
|
35
|
+
private _updated = Date.now();
|
|
33
36
|
private _ended?: number;
|
|
34
37
|
|
|
35
38
|
public constructor(
|
|
@@ -92,10 +95,16 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
|
|
|
92
95
|
const { appData, generateClientJoinedReport, joined = Date.now(), ...model } = config;
|
|
93
96
|
|
|
94
97
|
const result = new ObservedClient(model, this, appData);
|
|
98
|
+
const onUpdate = () => {
|
|
99
|
+
this._updated = Date.now();
|
|
100
|
+
this.emit('update');
|
|
101
|
+
};
|
|
95
102
|
|
|
96
103
|
result.once('close', () => {
|
|
104
|
+
result.off('update', onUpdate);
|
|
97
105
|
this._clients.delete(result.clientId);
|
|
98
106
|
});
|
|
107
|
+
result.on('update', onUpdate);
|
|
99
108
|
this._clients.set(result.clientId, result);
|
|
100
109
|
|
|
101
110
|
if (generateClientJoinedReport) {
|
package/src/ObservedClient.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { CallMetaType, createCallMetaReport } from './common/callMetaReports';
|
|
|
8
8
|
import { isValidUuid } from './common/utils';
|
|
9
9
|
import { createClientLeftEventReport } from './common/callEventReports';
|
|
10
10
|
import { CallEventType } from './common/CallEventType';
|
|
11
|
+
import { ObservedSfu } from './ObservedSfu';
|
|
11
12
|
|
|
12
13
|
const logger = createLogger('ObservedClient');
|
|
13
14
|
|
|
@@ -58,7 +59,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
58
59
|
|
|
59
60
|
public readonly created = Date.now();
|
|
60
61
|
public _updated = Date.now();
|
|
61
|
-
|
|
62
|
+
public sfuId?: string;
|
|
63
|
+
|
|
62
64
|
private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
|
|
63
65
|
|
|
64
66
|
private _closed = false;
|
|
@@ -77,10 +79,26 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
77
79
|
public totalDataChannelBytesReceived = 0;
|
|
78
80
|
public totalSentBytes = 0;
|
|
79
81
|
public totalReceivedBytes = 0;
|
|
82
|
+
public totalReceivedAudioBytes = 0;
|
|
83
|
+
public totalReceivedVideoBytes = 0;
|
|
84
|
+
public totalSentAudioBytes = 0;
|
|
85
|
+
public totalSentVideoBytes = 0;
|
|
86
|
+
|
|
87
|
+
public deltaReceivedAudioBytes = 0;
|
|
88
|
+
public deltaReceivedVideoBytes = 0;
|
|
89
|
+
public deltaSentAudioBytes = 0;
|
|
90
|
+
public deltaSentVideoBytes = 0;
|
|
91
|
+
public deltaDataChannelBytesSent = 0;
|
|
92
|
+
public deltaDataChannelBytesReceived = 0;
|
|
93
|
+
public deltaInboundPacketsLost = 0;
|
|
94
|
+
public deltaInboundPacketsReceived = 0;
|
|
95
|
+
public deltaOutboundPacketsSent = 0;
|
|
80
96
|
|
|
81
97
|
public avgRttInMs?: number;
|
|
82
|
-
public
|
|
83
|
-
public
|
|
98
|
+
public outboundAudioBitrate?: number;
|
|
99
|
+
public outboundVideoBitrate?: number;
|
|
100
|
+
public inboundAudioBitrate?: number;
|
|
101
|
+
public inboundVideoBitrate?: number;
|
|
84
102
|
|
|
85
103
|
public readonly mediaDevices: string[] = [];
|
|
86
104
|
public readonly codecs: string[] = [];
|
|
@@ -98,6 +116,12 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
98
116
|
this.setMaxListeners(Infinity);
|
|
99
117
|
}
|
|
100
118
|
|
|
119
|
+
public get sfu(): ObservedSfu | undefined {
|
|
120
|
+
if (!this.sfuId) return;
|
|
121
|
+
|
|
122
|
+
return this.call.observer.observedSfus.get(this.sfuId);
|
|
123
|
+
}
|
|
124
|
+
|
|
101
125
|
public get clientId(): string {
|
|
102
126
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
103
127
|
return this._model.clientId!;
|
|
@@ -203,6 +227,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
203
227
|
}
|
|
204
228
|
if (this._model.marker !== sample.marker) {
|
|
205
229
|
this._model.marker = sample.marker;
|
|
230
|
+
this._peerConnections.forEach((peerConnection) => (peerConnection.marker = sample.marker));
|
|
206
231
|
}
|
|
207
232
|
|
|
208
233
|
if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
|
|
@@ -668,40 +693,65 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
|
|
|
668
693
|
|
|
669
694
|
// update metrics
|
|
670
695
|
const wasUsingTURN = this.usingTURN;
|
|
696
|
+
const elapsedTimeInMs = now - this._updated;
|
|
671
697
|
|
|
672
698
|
this.usingTURN = false;
|
|
673
699
|
this.availableIncomingBitrate = 0;
|
|
674
700
|
this.availableOutgoingBitrate = 0;
|
|
675
|
-
this.
|
|
676
|
-
this.
|
|
677
|
-
this.
|
|
678
|
-
this.
|
|
679
|
-
this.
|
|
680
|
-
this.
|
|
681
|
-
this.
|
|
682
|
-
this.
|
|
683
|
-
this.
|
|
701
|
+
this.deltaInboundPacketsLost = 0;
|
|
702
|
+
this.deltaInboundPacketsReceived = 0;
|
|
703
|
+
this.deltaOutboundPacketsSent = 0;
|
|
704
|
+
this.deltaReceivedAudioBytes = 0;
|
|
705
|
+
this.deltaReceivedVideoBytes = 0;
|
|
706
|
+
this.deltaSentAudioBytes = 0;
|
|
707
|
+
this.deltaSentVideoBytes = 0;
|
|
708
|
+
this.deltaDataChannelBytesReceived = 0;
|
|
709
|
+
this.deltaDataChannelBytesSent = 0;
|
|
710
|
+
|
|
711
|
+
this.outboundAudioBitrate = 0;
|
|
712
|
+
this.outboundVideoBitrate = 0;
|
|
713
|
+
this.inboundAudioBitrate = 0;
|
|
714
|
+
this.inboundVideoBitrate = 0;
|
|
684
715
|
let sumRttInMs = 0;
|
|
685
716
|
|
|
686
717
|
for (const peerConnection of this._peerConnections.values()) {
|
|
687
718
|
if (peerConnection.closed) continue;
|
|
688
719
|
peerConnection.updateMetrics();
|
|
689
|
-
this.
|
|
690
|
-
this.
|
|
691
|
-
this.
|
|
692
|
-
this.
|
|
693
|
-
this.
|
|
694
|
-
this.
|
|
695
|
-
this.
|
|
696
|
-
this.
|
|
697
|
-
this.
|
|
720
|
+
this.deltaInboundPacketsLost += peerConnection.deltaInboundPacketsLost;
|
|
721
|
+
this.deltaInboundPacketsReceived += peerConnection.deltaInboundPacketsReceived;
|
|
722
|
+
this.deltaOutboundPacketsSent += peerConnection.deltaOutboundPacketsSent;
|
|
723
|
+
this.deltaReceivedAudioBytes += peerConnection.deltaReceivedAudioBytes;
|
|
724
|
+
this.deltaReceivedVideoBytes += peerConnection.deltaReceivedVideoBytes;
|
|
725
|
+
this.deltaSentAudioBytes += peerConnection.deltaSentAudioBytes;
|
|
726
|
+
this.deltaSentVideoBytes += peerConnection.deltaSentVideoBytes;
|
|
727
|
+
this.deltaDataChannelBytesReceived += peerConnection.deltaDataChannelBytesReceived;
|
|
728
|
+
this.deltaDataChannelBytesSent += peerConnection.deltaDataChannelBytesSent;
|
|
729
|
+
|
|
698
730
|
this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
|
|
699
731
|
this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
|
|
732
|
+
|
|
700
733
|
sumRttInMs += peerConnection.avgRttInMs ?? 0;
|
|
701
734
|
|
|
702
735
|
if (peerConnection.usingTURN) this.usingTURN = true;
|
|
703
736
|
}
|
|
704
737
|
|
|
738
|
+
this.totalSentBytes += this.deltaSentAudioBytes + this.deltaSentVideoBytes;
|
|
739
|
+
this.totalReceivedBytes += this.deltaReceivedAudioBytes + this.deltaReceivedVideoBytes;
|
|
740
|
+
this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
|
|
741
|
+
this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
|
|
742
|
+
this.totalSentAudioBytes += this.deltaSentAudioBytes;
|
|
743
|
+
this.totalSentVideoBytes += this.deltaSentVideoBytes;
|
|
744
|
+
this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
|
|
745
|
+
this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
|
|
746
|
+
this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
|
|
747
|
+
this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
|
|
748
|
+
this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
|
|
749
|
+
|
|
750
|
+
this.outboundAudioBitrate = (this.deltaSentAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
751
|
+
this.outboundVideoBitrate = (this.deltaSentVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
752
|
+
this.inboundAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
753
|
+
this.inboundVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
|
|
754
|
+
|
|
705
755
|
this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
|
|
706
756
|
|
|
707
757
|
if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
|
|
@@ -49,6 +49,7 @@ export class ObservedDataChannel extends EventEmitter {
|
|
|
49
49
|
private _closed = false;
|
|
50
50
|
private _updated = Date.now();
|
|
51
51
|
public bitrate = 0;
|
|
52
|
+
public marker?: string;
|
|
52
53
|
|
|
53
54
|
public totalReceivedMessages = 0;
|
|
54
55
|
public totalSentMessages = 0;
|
|
@@ -158,6 +159,7 @@ export class ObservedDataChannel extends EventEmitter {
|
|
|
158
159
|
...sample,
|
|
159
160
|
timestamp,
|
|
160
161
|
sampleSeq: -1,
|
|
162
|
+
marker: this.marker,
|
|
161
163
|
};
|
|
162
164
|
|
|
163
165
|
this.reports.addClientDataChannelReport(report);
|
package/src/ObservedICE.ts
CHANGED
|
@@ -27,6 +27,8 @@ export class ObservedICE extends EventEmitter {
|
|
|
27
27
|
return new ObservedICE(peerConnection);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
public marker?: string;
|
|
31
|
+
|
|
30
32
|
private readonly _localCandidates = new Map<string, IceLocalCandidate>();
|
|
31
33
|
private readonly _remoteCandidates = new Map<string, IceLocalCandidate>();
|
|
32
34
|
|
|
@@ -141,6 +143,7 @@ export class ObservedICE extends EventEmitter {
|
|
|
141
143
|
timestamp,
|
|
142
144
|
...candidatePair,
|
|
143
145
|
sampleSeq: -1, // deprecated
|
|
146
|
+
marker: this.marker,
|
|
144
147
|
};
|
|
145
148
|
|
|
146
149
|
this.reports.addIceCandidatePairReport(report);
|
|
@@ -58,6 +58,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
58
58
|
public bitrate = 0;
|
|
59
59
|
public rttInMs?: number;
|
|
60
60
|
public fractionLoss = 0;
|
|
61
|
+
public marker?: string;
|
|
61
62
|
|
|
62
63
|
public totalLostPackets = 0;
|
|
63
64
|
public totalReceivedPackets = 0;
|
|
@@ -197,6 +198,7 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
|
|
|
197
198
|
remoteUserId: this.remoteOutboundTrack?.peerConnection.client.userId,
|
|
198
199
|
remoteTrackId: this.remoteOutboundTrack?.trackId,
|
|
199
200
|
remotePeerConnectionId: this.remoteOutboundTrack?.peerConnection.peerConnectionId,
|
|
201
|
+
marker: this.marker,
|
|
200
202
|
};
|
|
201
203
|
|
|
202
204
|
if (this.kind === 'audio') this.reports.addInboundAudioTrackReport(report);
|
|
@@ -47,6 +47,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
47
47
|
|
|
48
48
|
public bitrate = 0;
|
|
49
49
|
public rttInMs?: number;
|
|
50
|
+
public marker?: string;
|
|
50
51
|
|
|
51
52
|
public totalLostPackets = 0;
|
|
52
53
|
public totalSentPackets = 0;
|
|
@@ -162,6 +163,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
162
163
|
...sample,
|
|
163
164
|
timestamp,
|
|
164
165
|
sampleSeq: -1,
|
|
166
|
+
marker: this.marker,
|
|
165
167
|
};
|
|
166
168
|
|
|
167
169
|
if (this.kind === 'audio') this.reports.addOutboundAudioTrackReport(report);
|
|
@@ -205,6 +207,7 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
|
|
|
205
207
|
this.totalLostPackets = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.packetsLost ?? 0), 0);
|
|
206
208
|
this.totalSentPackets = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.packetsSent ?? 0), 0);
|
|
207
209
|
this.totalSentBytes = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.bytesSent ?? 0), 0);
|
|
210
|
+
this.totalSentFrames = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.deltaSentPackets ?? 0), 0);
|
|
208
211
|
|
|
209
212
|
this.deltaEncodedFrames = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.deltaEncodedFrames ?? 0), 0);
|
|
210
213
|
this.deltaSentFrames = [ ...this._stats.values() ].reduce((acc, stat) => acc + (stat.deltaSentFrames ?? 0), 0);
|