@observertc/observer-js 0.40.8-beta → 0.40.10-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.
Files changed (65) hide show
  1. package/lib/ObservedClient.d.ts +5 -1
  2. package/lib/ObservedClient.d.ts.map +1 -1
  3. package/lib/ObservedClient.js +3 -1
  4. package/lib/ObservedDataChannel.d.ts +5 -1
  5. package/lib/ObservedDataChannel.d.ts.map +1 -1
  6. package/lib/ObservedDataChannel.js +3 -1
  7. package/lib/ObservedICE.d.ts +17 -1
  8. package/lib/ObservedICE.d.ts.map +1 -1
  9. package/lib/ObservedICE.js +37 -2
  10. package/lib/ObservedInboundTrack.d.ts +5 -1
  11. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  12. package/lib/ObservedInboundTrack.js +3 -1
  13. package/lib/ObservedOutboundTrack.d.ts +5 -1
  14. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  15. package/lib/ObservedOutboundTrack.js +3 -1
  16. package/lib/ObservedPeerConnection.d.ts +5 -1
  17. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  18. package/lib/ObservedPeerConnection.js +8 -4
  19. package/lib/ObservedSfu.d.ts +5 -1
  20. package/lib/ObservedSfu.d.ts.map +1 -1
  21. package/lib/ObservedSfu.js +6 -2
  22. package/lib/ObservedSfuInboundRtpPad.d.ts +5 -1
  23. package/lib/ObservedSfuInboundRtpPad.d.ts.map +1 -1
  24. package/lib/ObservedSfuInboundRtpPad.js +6 -2
  25. package/lib/ObservedSfuOutboundRtpPad.d.ts +5 -1
  26. package/lib/ObservedSfuOutboundRtpPad.d.ts.map +1 -1
  27. package/lib/ObservedSfuOutboundRtpPad.js +6 -2
  28. package/lib/ObservedSfuSctpChannel.d.ts +5 -1
  29. package/lib/ObservedSfuSctpChannel.d.ts.map +1 -1
  30. package/lib/ObservedSfuSctpChannel.js +6 -2
  31. package/lib/ObservedSfuTransport.d.ts +5 -1
  32. package/lib/ObservedSfuTransport.d.ts.map +1 -1
  33. package/lib/ObservedSfuTransport.js +6 -2
  34. package/lib/Observer.d.ts +7 -0
  35. package/lib/Observer.d.ts.map +1 -1
  36. package/lib/Observer.js +70 -0
  37. package/lib/index.d.ts +1 -0
  38. package/lib/index.d.ts.map +1 -1
  39. package/lib/{CallSummary.d.ts → monitors/CallSummary.d.ts} +7 -1
  40. package/lib/monitors/CallSummary.d.ts.map +1 -0
  41. package/lib/monitors/CallSummaryMonitor.d.ts +25 -0
  42. package/lib/monitors/CallSummaryMonitor.d.ts.map +1 -0
  43. package/lib/monitors/CallSummaryMonitor.js +82 -0
  44. package/lib/monitors/TurnUsageMonitor.d.ts +37 -0
  45. package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -0
  46. package/lib/monitors/TurnUsageMonitor.js +80 -0
  47. package/package.json +3 -3
  48. package/src/ObservedClient.ts +7 -3
  49. package/src/ObservedDataChannel.ts +6 -2
  50. package/src/ObservedICE.ts +53 -4
  51. package/src/ObservedInboundTrack.ts +6 -2
  52. package/src/ObservedOutboundTrack.ts +6 -2
  53. package/src/ObservedPeerConnection.ts +13 -6
  54. package/src/ObservedSfu.ts +10 -3
  55. package/src/ObservedSfuInboundRtpPad.ts +9 -3
  56. package/src/ObservedSfuOutboundRtpPad.ts +9 -3
  57. package/src/ObservedSfuSctpChannel.ts +9 -3
  58. package/src/ObservedSfuTransport.ts +10 -4
  59. package/src/Observer.ts +86 -0
  60. package/src/index.ts +1 -0
  61. package/src/{CallSummary.ts → monitors/CallSummary.ts} +8 -2
  62. package/src/monitors/CallSummaryMonitor.ts +107 -0
  63. package/src/monitors/TurnUsageMonitor.ts +124 -0
  64. package/lib/CallSummary.d.ts.map +0 -1
  65. /package/lib/{CallSummary.js → monitors/CallSummary.js} +0 -0
package/lib/Observer.d.ts CHANGED
@@ -5,6 +5,8 @@ import { EventEmitter } from 'events';
5
5
  import { PartialBy } from './common/utils';
6
6
  import { ObserverSinkContext } from './common/types';
7
7
  import { ObservedSfu, ObservedSfuModel } from './ObservedSfu';
8
+ import { CallSummaryMonitor } from './monitors/CallSummaryMonitor';
9
+ import { TurnUsageMonitor } from './monitors/TurnUsageMonitor';
8
10
  export type ObserverEvents = {
9
11
  'newcall': [ObservedCall];
10
12
  'newsfu': [ObservedSfu];
@@ -42,6 +44,7 @@ export declare class Observer extends EventEmitter {
42
44
  readonly reports: ReportsCollector;
43
45
  private readonly _observedCalls;
44
46
  private readonly _observedSfus;
47
+ private readonly _monitors;
45
48
  private _reportTimer?;
46
49
  private _closed;
47
50
  constructor(config: ObserverConfig);
@@ -50,6 +53,10 @@ export declare class Observer extends EventEmitter {
50
53
  started?: number;
51
54
  }): ObservedCall<T>;
52
55
  createObservedSfu<AppData extends Record<string, unknown> = Record<string, unknown>>(model: ObservedSfuModel, appData: AppData): ObservedSfu<AppData>;
56
+ createCallSummaryMonitor(options?: {
57
+ timeoutAfterCallClose?: number;
58
+ }): CallSummaryMonitor;
59
+ createTurnUsageMonitor(): TurnUsageMonitor;
53
60
  get observedCalls(): ReadonlyMap<string, ObservedCall>;
54
61
  get observedSfus(): ReadonlyMap<string, ObservedSfu>;
55
62
  get closed(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Observer.d.ts","sourceRoot":"","sources":["../src/Observer.ts"],"names":[],"mappings":"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"}
package/lib/Observer.js CHANGED
@@ -18,6 +18,8 @@ const ReportsCollector_1 = require("./ReportsCollector");
18
18
  const events_1 = require("events");
19
19
  const callEventReports_1 = require("./common/callEventReports");
20
20
  const ObservedSfu_1 = require("./ObservedSfu");
21
+ const CallSummaryMonitor_1 = require("./monitors/CallSummaryMonitor");
22
+ const TurnUsageMonitor_1 = require("./monitors/TurnUsageMonitor");
21
23
  const logger = (0, logger_1.createLogger)('Observer');
22
24
  class Observer extends events_1.EventEmitter {
23
25
  static create(providedConfig) {
@@ -39,6 +41,7 @@ class Observer extends events_1.EventEmitter {
39
41
  this.reports = new ReportsCollector_1.ReportsCollector();
40
42
  this._observedCalls = new Map();
41
43
  this._observedSfus = new Map();
44
+ this._monitors = new Map();
42
45
  this._closed = false;
43
46
  this.setMaxListeners(Infinity);
44
47
  logger.debug('Observer is created with config', this.config);
@@ -93,6 +96,73 @@ class Observer extends events_1.EventEmitter {
93
96
  this.emit('newsfu', sfu);
94
97
  return sfu;
95
98
  }
99
+ createCallSummaryMonitor(options) {
100
+ if (this._closed)
101
+ throw new Error('Cannot create a call summary monitor on a closed observer');
102
+ const existingMonitor = this._monitors.get(CallSummaryMonitor_1.CallSummaryMonitor.name);
103
+ if (existingMonitor)
104
+ return existingMonitor;
105
+ const monitor = new CallSummaryMonitor_1.CallSummaryMonitor();
106
+ const onNewCall = (call) => {
107
+ monitor.addCall(call);
108
+ call.once('close', () => {
109
+ var _a;
110
+ return setTimeout(() => {
111
+ const summary = monitor.takeSummary(call.callId);
112
+ summary && monitor.emit('summary', summary);
113
+ }, (_a = options === null || options === void 0 ? void 0 : options.timeoutAfterCallClose) !== null && _a !== void 0 ? _a : 1000);
114
+ });
115
+ };
116
+ monitor.once('close', () => {
117
+ this._monitors.delete(CallSummaryMonitor_1.CallSummaryMonitor.name);
118
+ this.off('newcall', onNewCall);
119
+ });
120
+ this._monitors.set(CallSummaryMonitor_1.CallSummaryMonitor.name, monitor);
121
+ this.on('newcall', onNewCall);
122
+ this.once('close', () => {
123
+ monitor.close();
124
+ });
125
+ return monitor;
126
+ }
127
+ createTurnUsageMonitor() {
128
+ if (this._closed)
129
+ throw new Error('Cannot create a turn usage monitor on a closed observer');
130
+ const existingMonitor = this._monitors.get(TurnUsageMonitor_1.TurnUsageMonitor.name);
131
+ if (existingMonitor)
132
+ return existingMonitor;
133
+ const monitor = new TurnUsageMonitor_1.TurnUsageMonitor();
134
+ const onNewCall = (call) => {
135
+ const onNewClient = (client) => {
136
+ const onNewPeerConnection = (pc) => {
137
+ const onUsingTurnChanged = (usingTurn) => {
138
+ if (usingTurn)
139
+ monitor.addPeerConnection(pc);
140
+ else
141
+ monitor.removePeerConnection(pc);
142
+ };
143
+ pc.once('close', () => {
144
+ pc.ICE.off('usingturnchanged', onUsingTurnChanged);
145
+ monitor.removePeerConnection(pc);
146
+ });
147
+ pc.ICE.on('usingturnchanged', onUsingTurnChanged);
148
+ };
149
+ client.once('close', () => client.off('newpeerconnection', onNewPeerConnection));
150
+ client.on('newpeerconnection', onNewPeerConnection);
151
+ };
152
+ call.once('close', () => call.off('newclient', onNewClient));
153
+ call.on('newclient', onNewClient);
154
+ };
155
+ monitor.once('close', () => {
156
+ this._monitors.delete(CallSummaryMonitor_1.CallSummaryMonitor.name);
157
+ this.off('newcall', onNewCall);
158
+ });
159
+ this._monitors.set(CallSummaryMonitor_1.CallSummaryMonitor.name, monitor);
160
+ this.on('newcall', onNewCall);
161
+ this.once('close', () => {
162
+ monitor.close();
163
+ });
164
+ return monitor;
165
+ }
96
166
  get observedCalls() {
97
167
  return this._observedCalls;
98
168
  }
package/lib/index.d.ts CHANGED
@@ -5,6 +5,7 @@ export * as ReportSchema from '@observertc/report-schemas-js';
5
5
  export type { LogLevel, Logger } from './common/logger';
6
6
  export type { Samples, ClientSample, SfuSample, ExtensionStat, PeerConnectionTransport, IceCandidatePair, MediaSourceStat, MediaCodecStats, InboundAudioTrack, InboundVideoTrack, OutboundAudioTrack, OutboundVideoTrack, IceLocalCandidate, IceRemoteCandidate, CustomCallEvent, SfuTransport, SfuInboundRtpPad, SfuOutboundRtpPad, SfuSctpChannel, SfuExtensionStats, DataChannel, } from '@observertc/sample-schemas-js';
7
7
  export type { CallEventReport, CallMetaReport, ClientDataChannelReport, ClientExtensionReport, IceCandidatePairReport, InboundAudioTrackReport, InboundVideoTrackReport, ObserverEventReport, OutboundAudioTrackReport, OutboundVideoTrackReport, PeerConnectionTransportReport, SfuEventReport, SfuExtensionReport, SfuInboundRtpPadReport, SfuMetaReport, SfuOutboundRtpPadReport, SfuSctpStreamReport, SFUTransportReport, } from '@observertc/report-schemas-js';
8
+ export type { ObservedCall, ObservedCallModel } from './ObservedCall';
8
9
  export type { ObservedClient, ObservedClientModel } from './ObservedClient';
9
10
  export type { ObservedPeerConnection, ObservedPeerConnectionModel, ObservedPeerConnectionEvents } from './ObservedPeerConnection';
10
11
  export type { ObservedInboundTrack, ObservedInboundTrackModel, ObservedInboundTrackEvents } from './ObservedInboundTrack';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAE9D,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAExD,YAAY,EACX,OAAO,EACP,YAAY,EACZ,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,WAAW,GACX,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACX,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAClI,YAAY,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC1H,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE9H,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtD,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,YAE9D;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA8B,MAAM,iBAAiB,CAAC;AAC/E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAG3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,YAAY,MAAM,+BAA+B,CAAC;AAE9D,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAExD,YAAY,EACX,OAAO,EACP,YAAY,EACZ,SAAS,EACT,aAAa,EACb,uBAAuB,EACvB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,WAAW,GACX,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EACX,eAAe,EACf,cAAc,EACd,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,mBAAmB,EACnB,wBAAwB,EACxB,wBAAwB,EACxB,6BAA6B,EAC7B,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,GAClB,MAAM,+BAA+B,CAAC;AAEvC,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,YAAY,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAClI,YAAY,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAC1H,YAAY,EAAE,qBAAqB,EAAE,0BAA0B,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAE9H,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE1D,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACtD,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,YAE9D;AAED,OAAO,EAAE,QAAQ,EAAE,MAAM,EAA8B,MAAM,iBAAiB,CAAC;AAC/E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAG3D"}
@@ -1,8 +1,14 @@
1
1
  export interface ClientSummary {
2
2
  clientId: string;
3
- userId: string;
3
+ mediaUnitId: string;
4
+ userId?: string;
4
5
  joined: number;
5
6
  durationInMs: number;
7
+ avgOutboundAudioBitrate: number;
8
+ avgOutboundVideoBitrate: number;
9
+ avgInboundAudioBitrate: number;
10
+ avgInboundVideoBitrate: number;
11
+ ewmaRttInMs: number;
6
12
  }
7
13
  export interface CallSummary {
8
14
  serviceId: string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallSummary.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummary.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,uBAAuB,EAAE,MAAM,CAAC;IAChC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,aAAa,EAAE,CAAC;CACzB"}
@@ -0,0 +1,25 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { CallSummary } from './CallSummary';
4
+ import { ObservedCall } from '../ObservedCall';
5
+ export type CallSummaryMonitorEvents = {
6
+ close: [];
7
+ summary: [CallSummary];
8
+ };
9
+ export declare interface CallSummaryMonitor {
10
+ on<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
11
+ off<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
12
+ once<U extends keyof CallSummaryMonitorEvents>(event: U, listener: (...args: CallSummaryMonitorEvents[U]) => void): this;
13
+ emit<U extends keyof CallSummaryMonitorEvents>(event: U, ...args: CallSummaryMonitorEvents[U]): boolean;
14
+ }
15
+ export declare class CallSummaryMonitor extends EventEmitter {
16
+ private readonly _summaries;
17
+ private _closed;
18
+ constructor();
19
+ addCall(call: ObservedCall): void;
20
+ private _addClient;
21
+ takeSummary(callId: string): CallSummary | undefined;
22
+ get closed(): boolean;
23
+ close(): void;
24
+ }
25
+ //# sourceMappingURL=CallSummaryMonitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallSummaryMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/CallSummaryMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG/C,MAAM,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,EAAE,CAAC;IACV,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC;CACvB,CAAA;AAED,MAAM,CAAC,OAAO,WAAW,kBAAkB;IAC1C,EAAE,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACvH,GAAG,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACxH,IAAI,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACzH,IAAI,CAAC,CAAC,SAAS,MAAM,wBAAwB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACxG;AAED,qBAAa,kBAAmB,SAAQ,YAAY;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAE7D,OAAO,CAAC,OAAO,CAAS;;IAKjB,OAAO,CAAC,IAAI,EAAE,YAAY;IAyBjC,OAAO,CAAC,UAAU;IAoCX,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAU3D,IAAW,MAAM,YAEhB;IAEM,KAAK;CAMZ"}
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CallSummaryMonitor = void 0;
4
+ const events_1 = require("events");
5
+ class CallSummaryMonitor extends events_1.EventEmitter {
6
+ constructor() {
7
+ super();
8
+ this._summaries = new Map();
9
+ this._closed = false;
10
+ }
11
+ addCall(call) {
12
+ if (this.closed)
13
+ return;
14
+ let callSummary = this._summaries.get(call.callId);
15
+ if (!callSummary) {
16
+ callSummary = {
17
+ callId: call.callId,
18
+ roomId: call.roomId,
19
+ serviceId: call.serviceId,
20
+ clients: [],
21
+ durationInMs: 0,
22
+ started: call.created,
23
+ };
24
+ this._summaries.set(call.callId, callSummary);
25
+ }
26
+ const constCallSummary = callSummary;
27
+ const onNewClient = (client) => this._addClient(constCallSummary, client);
28
+ call.once('close', () => {
29
+ call.off('newclient', onNewClient);
30
+ });
31
+ call.on('newclient', onNewClient);
32
+ }
33
+ _addClient(callSummary, client) {
34
+ if (this.closed)
35
+ return;
36
+ const clientSummary = {
37
+ clientId: client.clientId,
38
+ mediaUnitId: client.mediaUnitId,
39
+ durationInMs: 0,
40
+ avgInboundAudioBitrate: 0,
41
+ avgInboundVideoBitrate: 0,
42
+ avgOutboundAudioBitrate: 0,
43
+ avgOutboundVideoBitrate: 0,
44
+ ewmaRttInMs: 0,
45
+ joined: client.created,
46
+ userId: client.userId,
47
+ };
48
+ callSummary.clients.push(clientSummary);
49
+ const updateClient = () => {
50
+ if (client.avgRttInMs) {
51
+ clientSummary.ewmaRttInMs = (clientSummary.ewmaRttInMs * 0.9) + (client.avgRttInMs * 0.1);
52
+ }
53
+ };
54
+ client.on('update', updateClient);
55
+ client.once('close', () => {
56
+ const elapsedTimeInS = (Date.now() - client.created) / 1000;
57
+ clientSummary.avgInboundAudioBitrate = (client.totalReceivedBytes * 8) / elapsedTimeInS;
58
+ clientSummary.avgInboundVideoBitrate = (client.totalReceivedBytes * 8) / elapsedTimeInS;
59
+ clientSummary.avgOutboundAudioBitrate = (client.totalSentBytes * 8) / elapsedTimeInS;
60
+ clientSummary.avgOutboundVideoBitrate = (client.totalSentBytes * 8) / elapsedTimeInS;
61
+ clientSummary.durationInMs = elapsedTimeInS * 1000;
62
+ client.off('update', updateClient);
63
+ });
64
+ }
65
+ takeSummary(callId) {
66
+ if (this.closed)
67
+ return;
68
+ const summary = this._summaries.get(callId);
69
+ this._summaries.delete(callId);
70
+ return summary;
71
+ }
72
+ get closed() {
73
+ return this._closed;
74
+ }
75
+ close() {
76
+ if (this._closed)
77
+ return;
78
+ this._closed = true;
79
+ this.emit('close');
80
+ }
81
+ }
82
+ exports.CallSummaryMonitor = CallSummaryMonitor;
@@ -0,0 +1,37 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { ObservedPeerConnection } from '../ObservedPeerConnection';
4
+ export type TurnUsageMonitorEvents = {
5
+ close: [];
6
+ 'newturnip': [string];
7
+ update: [TurnUsage];
8
+ addpeerconnection: [ObservedPeerConnection];
9
+ removepeerconnection: [ObservedPeerConnection];
10
+ };
11
+ export type TurnUsage = {
12
+ turnIp: string;
13
+ totalBytesSent: number;
14
+ totalBytesReceived: number;
15
+ totalPacketsSent: number;
16
+ totalPacketsReceived: number;
17
+ };
18
+ export declare interface TurnUsageMonitor {
19
+ on<U extends keyof TurnUsageMonitorEvents>(event: U, listener: (...args: TurnUsageMonitorEvents[U]) => void): this;
20
+ off<U extends keyof TurnUsageMonitorEvents>(event: U, listener: (...args: TurnUsageMonitorEvents[U]) => void): this;
21
+ once<U extends keyof TurnUsageMonitorEvents>(event: U, listener: (...args: TurnUsageMonitorEvents[U]) => void): this;
22
+ emit<U extends keyof TurnUsageMonitorEvents>(event: U, ...args: TurnUsageMonitorEvents[U]): boolean;
23
+ }
24
+ export declare class TurnUsageMonitor extends EventEmitter {
25
+ private readonly _connections;
26
+ private readonly _turnUsage;
27
+ private _closed;
28
+ constructor();
29
+ addPeerConnection(peerConnection: ObservedPeerConnection): void;
30
+ removePeerConnection(peerConnection: ObservedPeerConnection): void;
31
+ get turnIps(): string[];
32
+ get peerConnections(): ObservedPeerConnection[];
33
+ getUsage(turnIp: string): TurnUsage | undefined;
34
+ get closed(): boolean;
35
+ close(): void;
36
+ }
37
+ //# sourceMappingURL=TurnUsageMonitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TurnUsageMonitor.d.ts","sourceRoot":"","sources":["../../src/monitors/TurnUsageMonitor.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAGnE,MAAM,MAAM,sBAAsB,GAAG;IACpC,KAAK,EAAE,EAAE,CAAC;IACV,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC;IACpB,iBAAiB,EAAE,CAAC,sBAAsB,CAAC,CAAC;IAC5C,oBAAoB,EAAE,CAAC,sBAAsB,CAAC,CAAC;CAC/C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC7B,CAAA;AAQD,MAAM,CAAC,OAAO,WAAW,gBAAgB;IACxC,EAAE,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACnH,GAAG,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACpH,IAAI,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,IAAI,CAAC;IACrH,IAAI,CAAC,CAAC,SAAS,MAAM,sBAAsB,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;CACpG;AAED,qBAAa,gBAAiB,SAAQ,YAAY;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAyC;IACtE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAE3D,OAAO,CAAC,OAAO,CAAS;;IAKjB,iBAAiB,CAAC,cAAc,EAAE,sBAAsB;IA4CxD,oBAAoB,CAAC,cAAc,EAAE,sBAAsB;IAelE,IAAW,OAAO,aAEjB;IAED,IAAW,eAAe,6BAEzB;IAEM,QAAQ,CAAC,MAAM,EAAE,MAAM;IAI9B,IAAW,MAAM,YAEhB;IAEM,KAAK;CAMZ"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TurnUsageMonitor = void 0;
4
+ const events_1 = require("events");
5
+ class TurnUsageMonitor extends events_1.EventEmitter {
6
+ constructor() {
7
+ super();
8
+ this._connections = new Map();
9
+ this._turnUsage = new Map();
10
+ this._closed = false;
11
+ }
12
+ addPeerConnection(peerConnection) {
13
+ if (this.closed)
14
+ return;
15
+ if (this._connections.has(peerConnection.peerConnectionId))
16
+ return;
17
+ const ice = peerConnection.ICE;
18
+ const onUpdate = () => {
19
+ var _a;
20
+ const turnIp = (_a = ice === null || ice === void 0 ? void 0 : ice.selectedRemoteCandidate) === null || _a === void 0 ? void 0 : _a.address;
21
+ if (!peerConnection.usingTURN || !turnIp)
22
+ return;
23
+ let usage = this._turnUsage.get(turnIp);
24
+ if (!usage) {
25
+ usage = {
26
+ turnIp,
27
+ totalBytesSent: 0,
28
+ totalBytesReceived: 0,
29
+ totalPacketsSent: 0,
30
+ totalPacketsReceived: 0,
31
+ };
32
+ this._turnUsage.set(turnIp, usage);
33
+ this.emit('newturnip', turnIp);
34
+ }
35
+ usage.totalBytesSent += ice.deltaBytesSent;
36
+ usage.totalBytesReceived += ice.deltaBytesReceived;
37
+ usage.totalPacketsSent += ice.deltaPacketsSent;
38
+ usage.totalPacketsReceived += ice.deltaPacketsReceived;
39
+ this.emit('update', usage);
40
+ };
41
+ peerConnection.ICE.on('update', onUpdate);
42
+ this._connections.set(peerConnection.peerConnectionId, {
43
+ peerConnection,
44
+ onUpdate
45
+ });
46
+ this.emit('addpeerconnection', peerConnection);
47
+ }
48
+ removePeerConnection(peerConnection) {
49
+ var _a;
50
+ if (this.closed)
51
+ return;
52
+ if (!this._connections.has(peerConnection.peerConnectionId))
53
+ return;
54
+ const { onUpdate } = (_a = this._connections.get(peerConnection.peerConnectionId)) !== null && _a !== void 0 ? _a : {};
55
+ if (!onUpdate)
56
+ return;
57
+ peerConnection.ICE.off('update', onUpdate);
58
+ this._connections.delete(peerConnection.peerConnectionId);
59
+ this.emit('removepeerconnection', peerConnection);
60
+ }
61
+ get turnIps() {
62
+ return Array.from(this._turnUsage.keys());
63
+ }
64
+ get peerConnections() {
65
+ return Array.from(this._connections.values()).map(({ peerConnection }) => peerConnection);
66
+ }
67
+ getUsage(turnIp) {
68
+ return this._turnUsage.get(turnIp);
69
+ }
70
+ get closed() {
71
+ return this._closed;
72
+ }
73
+ close() {
74
+ if (this._closed)
75
+ return;
76
+ this._closed = true;
77
+ this.emit('close');
78
+ }
79
+ }
80
+ exports.TurnUsageMonitor = TurnUsageMonitor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@observertc/observer-js",
3
- "version": "0.40.8-beta",
3
+ "version": "0.40.10-beta",
4
4
  "description": "Server Side NodeJS Library for processing ObserveRTC Samples",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -31,12 +31,12 @@
31
31
  "uuid": "^8.3.2"
32
32
  },
33
33
  "devDependencies": {
34
+ "@types/events": "^3.0.0",
34
35
  "@types/jest": "^27.5.2",
35
36
  "@types/node": "^20.9.0",
37
+ "@types/uuid": "^8.3.4",
36
38
  "@typescript-eslint/eslint-plugin": "^5.38.0",
37
39
  "@typescript-eslint/parser": "^5.38.0",
38
- "@types/events": "^3.0.0",
39
- "@types/uuid": "^8.3.4",
40
40
  "bufferutil": "^4.0.6",
41
41
  "eslint": "^8.24.0",
42
42
  "jest": "^27.5.0",
@@ -24,7 +24,9 @@ export type ObservedClientModel= {
24
24
  };
25
25
 
26
26
  export type ObservedClientEvents = {
27
- update: [],
27
+ update: [{
28
+ elapsedTimeInMs: number,
29
+ }],
28
30
  close: [],
29
31
  newpeerconnection: [ObservedPeerConnection],
30
32
  iceconnectionstatechange: [{
@@ -758,9 +760,11 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
758
760
  this.inboundVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
759
761
 
760
762
  this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
761
-
763
+
762
764
  this._updated = now;
763
- this.emit('update');
765
+ this.emit('update', {
766
+ elapsedTimeInMs,
767
+ });
764
768
  }
765
769
 
766
770
  private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
@@ -10,7 +10,9 @@ export type ObservedDataChannelModel = {
10
10
  }
11
11
 
12
12
  export type ObservedDataChannelEvents = {
13
- update: [],
13
+ update: [{
14
+ elapsedTimeInMs: number;
15
+ }],
14
16
  close: [],
15
17
  };
16
18
 
@@ -184,6 +186,8 @@ export class ObservedDataChannel extends EventEmitter {
184
186
 
185
187
  this._stats = sample;
186
188
  this._updated = timestamp;
187
- this.emit('update');
189
+ this.emit('update', {
190
+ elapsedTimeInMs,
191
+ });
188
192
  }
189
193
  }
@@ -5,13 +5,16 @@ import { IceCandidatePairReport } from '@observertc/report-schemas-js';
5
5
  import { CallMetaType, createCallMetaReport } from './common/callMetaReports';
6
6
 
7
7
  export type ObservedICEEvents = {
8
- update: [],
8
+ update: [{
9
+ elapsedTimeInMs: number;
10
+ }],
9
11
  'new-local-candidate': [IceLocalCandidate],
10
12
  'new-remote-candidate': [IceRemoteCandidate],
11
13
  'new-selected-candidate-pair': [{
12
14
  localCandidate: IceLocalCandidate,
13
15
  remoteCandidate: IceRemoteCandidate,
14
16
  }],
17
+ usingturnchanged: [boolean],
15
18
  close: [],
16
19
  };
17
20
 
@@ -32,6 +35,20 @@ export class ObservedICE extends EventEmitter {
32
35
  private readonly _localCandidates = new Map<string, IceLocalCandidate>();
33
36
  private readonly _remoteCandidates = new Map<string, IceLocalCandidate>();
34
37
 
38
+ public usingTURN = false;
39
+
40
+ public deltaBytesReceived = 0;
41
+ public deltaBytesSent = 0;
42
+ public deltaPacketsReceived = 0;
43
+ public deltaPacketsSent = 0;
44
+
45
+ public totalBytesReceived = 0;
46
+ public totalBytesSent = 0;
47
+ public totalPacketsReceived = 0;
48
+ public totalPacketsSent = 0;
49
+
50
+ public currentRttInMs?: number;
51
+
35
52
  private _selectedLocalCandidateId?: string;
36
53
  private _selectedRemoteCandidateId?: string;
37
54
  private _updated = Date.now();
@@ -131,8 +148,18 @@ export class ObservedICE extends EventEmitter {
131
148
  }
132
149
  }
133
150
 
134
- public update(candidatePair: IceCandidatePair, timestamp: number) {
151
+ public resetMetrics() {
152
+ this.deltaBytesReceived = 0;
153
+ this.deltaBytesSent = 0;
154
+ this.deltaPacketsReceived = 0;
155
+ this.deltaPacketsSent = 0;
135
156
 
157
+ this.currentRttInMs = undefined;
158
+ }
159
+
160
+ public update(candidatePair: IceCandidatePair, timestamp: number) {
161
+ const now = Date.now();
162
+ const elapsedTimeInMs = now - this._updated;
136
163
  const report: IceCandidatePairReport = {
137
164
  serviceId: this.peerConnection.client.serviceId,
138
165
  mediaUnitId: this.peerConnection.client.mediaUnitId,
@@ -149,6 +176,18 @@ export class ObservedICE extends EventEmitter {
149
176
  this.reports.addIceCandidatePairReport(report);
150
177
 
151
178
  if (!candidatePair.nominated) return;
179
+
180
+ this.deltaBytesReceived = (candidatePair.bytesReceived ?? 0) - (this._stats?.bytesReceived ?? 0);
181
+ this.deltaBytesSent = (candidatePair.bytesSent ?? 0) - (this._stats?.bytesSent ?? 0);
182
+ this.deltaPacketsReceived = (candidatePair.packetsReceived ?? 0) - (this._stats?.packetsReceived ?? 0);
183
+ this.deltaPacketsSent = (candidatePair.packetsSent ?? 0) - (this._stats?.packetsSent ?? 0);
184
+
185
+ this.totalBytesReceived += this.deltaBytesReceived;
186
+ this.totalBytesSent += this.deltaBytesSent;
187
+ this.totalPacketsReceived += this.deltaPacketsReceived;
188
+ this.totalPacketsSent += this.deltaPacketsSent;
189
+
190
+ this.currentRttInMs = candidatePair.currentRoundTripTime ? candidatePair.currentRoundTripTime * 1000 : undefined;
152
191
 
153
192
  this._stats = candidatePair;
154
193
 
@@ -167,14 +206,24 @@ export class ObservedICE extends EventEmitter {
167
206
  const remoteCandidate = this._remoteCandidates.get(candidatePair.remoteCandidateId);
168
207
 
169
208
  if (localCandidate && remoteCandidate) {
209
+ const wasUsingTURN = this.usingTURN;
210
+
211
+ this.usingTURN = remoteCandidate.candidateType?.toLocaleLowerCase() === 'relay';
212
+
170
213
  this.emit('new-selected-candidate-pair', {
171
214
  localCandidate,
172
215
  remoteCandidate,
173
216
  });
217
+
218
+ if (wasUsingTURN !== this.usingTURN) {
219
+ this.emit('usingturnchanged', this.usingTURN);
220
+ }
174
221
  }
175
222
  }
176
223
 
177
- this._updated = timestamp;
178
- this.emit('update');
224
+ this._updated = now;
225
+ this.emit('update', {
226
+ elapsedTimeInMs,
227
+ });
179
228
  }
180
229
  }
@@ -13,7 +13,9 @@ export type ObservedInboundTrackModel<K extends MediaKind> = {
13
13
  }
14
14
 
15
15
  export type ObservedInboundTrackEvents<K extends MediaKind> = {
16
- update: [],
16
+ update: [{
17
+ elapsedTimeInMs: number;
18
+ }],
17
19
  close: [],
18
20
  remoteoutboundtrack: [ObservedOutboundTrack<K>],
19
21
  };
@@ -272,7 +274,9 @@ export class ObservedInboundTrack<Kind extends MediaKind> extends EventEmitter {
272
274
  this._stats.set(sample.ssrc, stats);
273
275
 
274
276
  this._updated = now;
275
- this.emit('update');
277
+ this.emit('update', {
278
+ elapsedTimeInMs,
279
+ });
276
280
  }
277
281
 
278
282
  public updateMetrics() {
@@ -12,7 +12,9 @@ export type ObservedOutboundTrackModel<K extends MediaKind> = {
12
12
  }
13
13
 
14
14
  export type ObservedOutboundTrackEvents = {
15
- update: [],
15
+ update: [{
16
+ elapsedTimeInMs: number;
17
+ }],
16
18
  close: [],
17
19
  };
18
20
 
@@ -242,7 +244,9 @@ export class ObservedOutboundTrack<Kind extends MediaKind> extends EventEmitter
242
244
  }
243
245
 
244
246
  this._updated = now;
245
- this.emit('update');
247
+ this.emit('update', {
248
+ elapsedTimeInMs,
249
+ });
246
250
  }
247
251
 
248
252
  public connectInboundTrack(track: ObservedInboundTrack<Kind>) {