@observertc/observer-js 1.0.1-c3edea3.0 → 1.0.1-cda37f7.0

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 (140) hide show
  1. package/lib/ObservedCall.d.ts +43 -7
  2. package/lib/ObservedCall.d.ts.map +1 -1
  3. package/lib/ObservedCall.js +129 -13
  4. package/lib/ObservedCallEventMonitor.d.ts +104 -0
  5. package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
  6. package/lib/ObservedCallEventMonitor.js +314 -0
  7. package/lib/ObservedCallSummary.d.ts +18 -0
  8. package/lib/ObservedCallSummary.d.ts.map +1 -0
  9. package/lib/ObservedClient.d.ts +70 -11
  10. package/lib/ObservedClient.d.ts.map +1 -1
  11. package/lib/ObservedClient.js +392 -72
  12. package/lib/ObservedClientEventMonitor.d.ts +89 -0
  13. package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
  14. package/lib/ObservedClientEventMonitor.js +247 -0
  15. package/lib/ObservedClientSummary.d.ts +23 -0
  16. package/lib/ObservedClientSummary.d.ts.map +1 -0
  17. package/lib/ObservedClientSummary.js +2 -0
  18. package/lib/ObservedDataChannel.d.ts +6 -0
  19. package/lib/ObservedDataChannel.d.ts.map +1 -1
  20. package/lib/ObservedDataChannel.js +30 -0
  21. package/lib/ObservedIceCandidatePair.d.ts +6 -1
  22. package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
  23. package/lib/ObservedIceCandidatePair.js +45 -1
  24. package/lib/ObservedIceTransport.d.ts +4 -0
  25. package/lib/ObservedIceTransport.d.ts.map +1 -1
  26. package/lib/ObservedIceTransport.js +28 -0
  27. package/lib/ObservedInboundTrack.d.ts +2 -0
  28. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  29. package/lib/ObservedInboundTrack.js +2 -0
  30. package/lib/ObservedOutboundTrack.d.ts +2 -0
  31. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  32. package/lib/ObservedOutboundTrack.js +2 -0
  33. package/lib/ObservedPeerConnection.d.ts +29 -2
  34. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  35. package/lib/ObservedPeerConnection.js +181 -29
  36. package/lib/ObservedTURN.d.ts +31 -0
  37. package/lib/ObservedTURN.d.ts.map +1 -0
  38. package/lib/ObservedTURN.js +58 -0
  39. package/lib/ObservedTurnServer.d.ts +25 -0
  40. package/lib/ObservedTurnServer.d.ts.map +1 -0
  41. package/lib/ObservedTurnServer.js +59 -0
  42. package/lib/Observer.d.ts +43 -22
  43. package/lib/Observer.d.ts.map +1 -1
  44. package/lib/Observer.js +126 -40
  45. package/lib/ObserverEventMonitor.d.ts +130 -0
  46. package/lib/ObserverEventMonitor.d.ts.map +1 -0
  47. package/lib/ObserverEventMonitor.js +404 -0
  48. package/lib/ObserverSummary.d.ts +13 -0
  49. package/lib/ObserverSummary.d.ts.map +1 -0
  50. package/lib/ObserverSummary.js +2 -0
  51. package/lib/common/utils.d.ts +2 -1
  52. package/lib/common/utils.d.ts.map +1 -1
  53. package/lib/common/utils.js +11 -3
  54. package/lib/index.d.ts +6 -0
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.js +9 -1
  57. package/lib/schema/ClientEventTypes.d.ts +160 -0
  58. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  59. package/lib/schema/ClientEventTypes.js +38 -0
  60. package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
  61. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  62. package/lib/schema/ClientMetaTypes.js +16 -0
  63. package/lib/schema/ClientSample.d.ts +1 -1
  64. package/lib/schema/ClientSample.d.ts.map +1 -1
  65. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  66. package/lib/updaters/CallUpdater.js +2 -0
  67. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  68. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  69. package/lib/updaters/ObserverUpdater.js +2 -0
  70. package/lib/updaters/OnAllCallObserverUpdater.d.ts +15 -0
  71. package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
  72. package/lib/updaters/OnAllCallObserverUpdater.js +50 -0
  73. package/lib/updaters/OnAllClientCallUpdater.d.ts +15 -0
  74. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  75. package/lib/updaters/OnAllClientCallUpdater.js +53 -0
  76. package/lib/updaters/OnAnyCallObserverUpdater.d.ts +12 -0
  77. package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
  78. package/lib/updaters/OnAnyCallObserverUpdater.js +37 -0
  79. package/lib/updaters/OnAnyClientCallUpdater.d.ts +12 -0
  80. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  81. package/lib/updaters/OnAnyClientCallUpdater.js +36 -0
  82. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  83. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  84. package/lib/updaters/OnIntervalUpdater.js +17 -0
  85. package/lib/updaters/Updater.d.ts +6 -0
  86. package/lib/updaters/Updater.d.ts.map +1 -0
  87. package/lib/updaters/Updater.js +2 -0
  88. package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
  89. package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
  90. package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
  91. package/package.json +1 -1
  92. package/src/ObservedCall.ts +210 -16
  93. package/src/ObservedCallEventMonitor.ts +392 -0
  94. package/src/ObservedCallSummary.ts +22 -0
  95. package/src/ObservedClient.ts +490 -79
  96. package/src/ObservedClientEventMonitor.ts +301 -0
  97. package/src/ObservedClientSummary.ts +24 -0
  98. package/src/ObservedDataChannel.ts +32 -0
  99. package/src/ObservedIceCandidatePair.ts +44 -2
  100. package/src/ObservedIceTransport.ts +29 -0
  101. package/src/ObservedInboundTrack.ts +3 -0
  102. package/src/ObservedOutboundTrack.ts +3 -0
  103. package/src/ObservedPeerConnection.ts +210 -46
  104. package/src/ObservedTURN.ts +86 -0
  105. package/src/ObservedTurnServer.ts +72 -0
  106. package/src/Observer.ts +179 -64
  107. package/src/ObserverEventMonitor.ts +518 -0
  108. package/src/ObserverSummary.ts +15 -0
  109. package/src/common/utils.ts +12 -2
  110. package/src/index.ts +6 -0
  111. package/src/schema/ClientEventTypes.ts +176 -0
  112. package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
  113. package/src/schema/ClientSample.ts +1 -1
  114. package/src/updaters/ObserverUpdater.ts +5 -0
  115. package/src/updaters/OnAllCallObserverUpdater.ts +59 -0
  116. package/src/updaters/OnAllClientCallUpdater.ts +61 -0
  117. package/src/updaters/OnAnyCallObserverUpdater.ts +41 -0
  118. package/src/updaters/OnAnyClientCallUpdater.ts +39 -0
  119. package/src/updaters/OnIntervalUpdater.ts +19 -0
  120. package/src/updaters/Updater.ts +5 -0
  121. package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
  122. package/tsconfig.json +1 -1
  123. package/lib/schema/eventTypes.d.ts +0 -33
  124. package/lib/schema/eventTypes.d.ts.map +0 -1
  125. package/lib/schema/eventTypes.js +0 -38
  126. package/lib/schema/metaTypes.d.ts.map +0 -1
  127. package/lib/schema/metaTypes.js +0 -16
  128. package/lib/utils/CallUpdater.d.ts.map +0 -1
  129. package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
  130. package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
  131. package/lib/utils/OnAllClientCallUpdater.js +0 -58
  132. package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
  133. package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
  134. package/lib/utils/onAnyClientCallUpdater.js +0 -51
  135. package/src/schema/eventTypes.ts +0 -36
  136. package/src/utils/OnAllClientCallUpdater.ts +0 -68
  137. package/src/utils/onAnyClientCallUpdater.ts +0 -59
  138. /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
  139. /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
  140. /package/src/{utils → updaters}/CallUpdater.ts +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Updater.d.ts","sourceRoot":"","sources":["../../src/updaters/Updater.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACd"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,25 @@
1
+ import { ObservedCall } from '../ObservedCall';
2
+ import { ObservedCallEventMonitor } from '../ObservedCallEventMonitor';
3
+ import { ObservedInboundTrack } from '../ObservedInboundTrack';
4
+ import { ObservedOutboundTrack } from '../ObservedOutboundTrack';
5
+ import { RemoteTrackResolver } from './RemoteTrackResolver';
6
+ export declare class MediasoupRemoteTrackResolver implements RemoteTrackResolver {
7
+ readonly observedCall: ObservedCall;
8
+ readonly eventMonitor: ObservedCallEventMonitor<{}>;
9
+ private _consumerIdToProducerId;
10
+ private _producerIdToOutboundTrack;
11
+ private _consumerIdToInboundTrack;
12
+ private _inboundTrackToConsumerId;
13
+ private _producerIdToConsumerIds;
14
+ private _outboundTrackToProducerId;
15
+ constructor(observedCall: ObservedCall);
16
+ resolveRemoteOutboundTrack(inboundTrack: ObservedInboundTrack): ObservedOutboundTrack | undefined;
17
+ resolveRemoteInboundTracks(outboundTrack: ObservedOutboundTrack): ObservedInboundTrack[] | undefined;
18
+ private _addInboundTrack;
19
+ private _removeInboundTrack;
20
+ private _addOutboundTrack;
21
+ private _removeOutboundTrack;
22
+ private _getInboundTrackAttachments;
23
+ private _getOutboundTrackAttachments;
24
+ }
25
+ //# sourceMappingURL=MediasoupRemoteTrackResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediasoupRemoteTrackResolver.d.ts","sourceRoot":"","sources":["../../src/utils/MediasoupRemoteTrackResolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,qBAAa,4BAA6B,YAAW,mBAAmB;aAetD,YAAY,EAAE,YAAY;IAd3C,SAAgB,YAAY,EAAE,wBAAwB,CAAC,EAEtD,CAAC,CAAC;IAEH,OAAO,CAAC,uBAAuB,CAA6B;IAC5D,OAAO,CAAC,0BAA0B,CAA4C;IAC9E,OAAO,CAAC,yBAAyB,CAA2C;IAG5E,OAAO,CAAC,yBAAyB,CAA6B;IAC9D,OAAO,CAAC,wBAAwB,CAA+B;IAC/D,OAAO,CAAC,0BAA0B,CAA6B;gBAG9C,YAAY,EAAE,YAAY;IAcpC,0BAA0B,CAAC,YAAY,EAAE,oBAAoB,GAAG,qBAAqB,GAAG,SAAS;IAYjG,0BAA0B,CAAC,aAAa,EAAE,qBAAqB,GAAG,oBAAoB,EAAE,GAAG,SAAS;IAe3G,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,2BAA2B;IAcnC,OAAO,CAAC,4BAA4B;CAWpC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MediasoupRemoteTrackResolver = void 0;
4
+ class MediasoupRemoteTrackResolver {
5
+ observedCall;
6
+ eventMonitor;
7
+ _consumerIdToProducerId = new Map();
8
+ _producerIdToOutboundTrack = new Map();
9
+ _consumerIdToInboundTrack = new Map();
10
+ // private _producerIdToOutboundTrack = new Map<string, ObservedOutboundTrack>();
11
+ _inboundTrackToConsumerId = new Map();
12
+ _producerIdToConsumerIds = new Map();
13
+ _outboundTrackToProducerId = new Map();
14
+ constructor(observedCall) {
15
+ this.observedCall = observedCall;
16
+ this.eventMonitor = this.observedCall.createEventMonitor({});
17
+ this.eventMonitor.onInboundTrackAdded = this._addInboundTrack.bind(this);
18
+ this.eventMonitor.onInboundTrackRemoved = this._removeInboundTrack.bind(this);
19
+ this.eventMonitor.onOutboundTrackAdded = this._addOutboundTrack.bind(this);
20
+ this.eventMonitor.onOutboundTrackRemoved = this._removeOutboundTrack.bind(this);
21
+ // this.eventMonitor.onClientEvent = (client, event) => {
22
+ // };
23
+ }
24
+ resolveRemoteOutboundTrack(inboundTrack) {
25
+ const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
26
+ if (!consumerId)
27
+ return;
28
+ const producerId = this._consumerIdToProducerId.get(consumerId);
29
+ if (!producerId)
30
+ return;
31
+ return this._producerIdToOutboundTrack.get(producerId);
32
+ }
33
+ resolveRemoteInboundTracks(outboundTrack) {
34
+ const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
35
+ if (!producerId)
36
+ return;
37
+ const consumerIds = this._producerIdToConsumerIds.get(producerId);
38
+ if (!consumerIds)
39
+ return;
40
+ return consumerIds
41
+ .map((consumerId) => this._consumerIdToInboundTrack.get(consumerId))
42
+ .filter((inboundTrack) => Boolean(inboundTrack));
43
+ }
44
+ _addInboundTrack(inboundTrack) {
45
+ const attachments = this._getInboundTrackAttachments(inboundTrack);
46
+ if (!attachments)
47
+ return;
48
+ const { producerId, consumerId } = attachments;
49
+ this._inboundTrackToConsumerId.set(inboundTrack.id, consumerId);
50
+ this._consumerIdToProducerId.set(consumerId, producerId);
51
+ this._consumerIdToInboundTrack.set(consumerId, inboundTrack);
52
+ let producerConsumers = this._producerIdToConsumerIds.get(producerId);
53
+ if (!producerConsumers) {
54
+ producerConsumers = [];
55
+ this._producerIdToConsumerIds.set(producerId, producerConsumers);
56
+ }
57
+ producerConsumers.push(consumerId);
58
+ }
59
+ _removeInboundTrack(inboundTrack) {
60
+ const consumerId = this._inboundTrackToConsumerId.get(inboundTrack.id);
61
+ if (!consumerId)
62
+ return;
63
+ this._inboundTrackToConsumerId.delete(inboundTrack.id);
64
+ this._consumerIdToProducerId.delete(consumerId);
65
+ this._consumerIdToInboundTrack.delete(consumerId);
66
+ const producerConsumers = this._producerIdToConsumerIds.get(consumerId);
67
+ if (!producerConsumers)
68
+ return;
69
+ const filteredProducerConsumers = producerConsumers.filter((id) => id !== consumerId);
70
+ if (filteredProducerConsumers.length === 0) {
71
+ this._producerIdToConsumerIds.delete(consumerId);
72
+ }
73
+ else {
74
+ this._producerIdToConsumerIds.set(consumerId, filteredProducerConsumers);
75
+ }
76
+ }
77
+ _addOutboundTrack(outboundTrack) {
78
+ const attachments = this._getOutboundTrackAttachments(outboundTrack);
79
+ if (!attachments)
80
+ return;
81
+ const { producerId, } = attachments;
82
+ this._producerIdToOutboundTrack.set(producerId, outboundTrack);
83
+ this._outboundTrackToProducerId.set(outboundTrack.id, producerId);
84
+ }
85
+ _removeOutboundTrack(outboundTrack) {
86
+ const producerId = this._outboundTrackToProducerId.get(outboundTrack.id);
87
+ if (!producerId)
88
+ return;
89
+ this._producerIdToOutboundTrack.delete(producerId);
90
+ this._outboundTrackToProducerId.delete(outboundTrack.id);
91
+ }
92
+ _getInboundTrackAttachments(inboundTrack) {
93
+ const { producerId, consumerId } = inboundTrack.attachments ?? {};
94
+ if (!producerId || !consumerId || typeof producerId !== 'string' || typeof consumerId !== 'string')
95
+ return;
96
+ return {
97
+ producerId,
98
+ consumerId
99
+ };
100
+ }
101
+ _getOutboundTrackAttachments(outboundTrack) {
102
+ const { producerId, } = outboundTrack.attachments ?? {};
103
+ if (!producerId || typeof producerId !== 'string')
104
+ return;
105
+ return {
106
+ producerId,
107
+ };
108
+ }
109
+ }
110
+ exports.MediasoupRemoteTrackResolver = MediasoupRemoteTrackResolver;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@observertc/observer-js",
3
- "version": "1.0.1-c3edea3.0",
3
+ "version": "1.0.1-cda37f7.0",
4
4
  "description": "Server Side NodeJS Library for processing ObserveRTC Samples",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -6,15 +6,18 @@ import { CalculatedScore } from './scores/CalculatedScore';
6
6
  import { DefaultCallScoreCalculator } from './scores/DefaultCallScoreCalculator';
7
7
  import { Detectors } from './detectors/Detectors';
8
8
  import { RemoteTrackResolver } from './utils/RemoteTrackResolver';
9
- import { CallUpdater } from './utils/CallUpdater';
10
- import { OnAllClientCallUpdater } from './utils/OnAllClientCallUpdater';
11
- import { OnAnyClientCallUpdater } from './utils/onAnyClientCallUpdater';
9
+ import { OnAllClientCallUpdater } from './updaters/OnAllClientCallUpdater';
10
+ import { Updater } from './updaters/Updater';
11
+ import { OnIntervalUpdater } from './updaters/OnIntervalUpdater';
12
+ import { OnAnyClientCallUpdater } from './updaters/OnAnyClientCallUpdater';
13
+ import { ObservedCallEventMonitor } from './ObservedCallEventMonitor';
12
14
 
13
15
  export type ObservedCallSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
14
16
  callId: string;
15
17
  appData?: AppData;
16
18
  remoteTrackResolvePolicy?: 'p2p' | 'mediasoup-sfu',
17
- callUpdaterPolicy?: 'onAnyClientUpdate' | 'onAllClientsUpdate',
19
+ updatePolicy?: 'update-on-any-client-updated' | 'update-when-all-client-updated' | 'update-on-interval',
20
+ updateIntervalInMs?: number,
18
21
  };
19
22
 
20
23
  export type ObservedCallEvents = {
@@ -34,20 +37,62 @@ export declare interface ObservedCall {
34
37
 
35
38
  export class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
36
39
  public readonly detectors: Detectors;
40
+ public updater?: Updater;
41
+ public scoreCalculator: ScoreCalculator;
37
42
  public readonly callId: string;
38
43
  public readonly observedClients = new Map<string, ObservedClient>();
44
+ public readonly clientsUsedTurn = new Set<string>();
39
45
  public readonly calculatedScore: CalculatedScore = {
40
46
  weight: 1,
41
47
  value: undefined,
42
48
  };
43
49
  public remoteTrackResolver?: RemoteTrackResolver;
44
- public callUpdater?: CallUpdater;
45
50
 
46
- public appData?: AppData;
51
+ public totalAddedClients = 0;
52
+ public totalRemovedClients = 0;
53
+
54
+ public totalClientsReceivedAudioBytes = 0;
55
+ public totalClientsReceivedVideoBytes = 0;
56
+ public totalClientsReceivedDataChannelBytes = 0;
57
+ public totalClientsReceivedBytes = 0;
58
+
59
+ public totalClientsSentAudioBytes = 0;
60
+ public totalClientsSentDataChannelBytes = 0;
61
+ public totalClientsSentVideoBytes = 0;
62
+ public totalClientsSentBytes = 0;
63
+
64
+ public totalRttLt50Measurements = 0;
65
+ public totalRttLt150Measurements = 0;
66
+ public totalRttLt300Measurements = 0;
67
+ public totalRttGtOrEq300Measurements = 0;
68
+
69
+ public numberOfIssues = 0;
70
+ public numberOfPeerConnections = 0;
71
+ public numberOfInboundRtpStreams = 0;
72
+ public numberOfOutboundRtpStreams = 0;
73
+ public numberOfDataChannels = 0;
74
+
75
+ public maxNumberOfClients = 0;
76
+ public deltaNumberOfIssues = 0;
77
+
78
+ public deltaRttLt50Measurements = 0;
79
+ public deltaRttLt150Measurements = 0;
80
+ public deltaRttLt300Measurements = 0;
81
+ public deltaRttGtOrEq300Measurements = 0;
82
+
83
+ public appData: AppData;
47
84
  public closed = false;
48
- public started?: number;
49
- public ended?: number;
50
- public scoreCalculator: ScoreCalculator;
85
+ public startedAt?: number;
86
+ public endedAt?: number;
87
+ public closedAt?: number;
88
+
89
+ private _callStartedEvent: {
90
+ emitted: boolean,
91
+ timer?: ReturnType<typeof setTimeout>,
92
+ };
93
+ private _callEndedEvent: {
94
+ emitted: boolean
95
+ };
51
96
 
52
97
  public constructor(
53
98
  settings: ObservedCallSettings<AppData>,
@@ -57,16 +102,30 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
57
102
  this.setMaxListeners(Infinity);
58
103
 
59
104
  this.callId = settings.callId;
60
- this.appData = settings.appData;
105
+ this.appData = settings.appData ?? {} as AppData;
61
106
  this.scoreCalculator = new DefaultCallScoreCalculator(this);
62
107
  this.detectors = new Detectors();
63
108
 
64
- switch (settings.callUpdaterPolicy) {
65
- case 'onAllClientsUpdate':
66
- this.callUpdater = new OnAllClientCallUpdater(this);
109
+ if (settings.updateIntervalInMs) {
110
+ if (settings.updatePolicy !== 'update-on-interval') {
111
+ throw new Error('updatePolicy must be update-on-interval if updateIntervalInMs is set in config');
112
+ }
113
+ }
114
+ switch (settings.updatePolicy) {
115
+ case 'update-on-any-client-updated':
116
+ this.updater = new OnAllClientCallUpdater(this);
117
+ break;
118
+ case 'update-when-all-client-updated':
119
+ this.updater = new OnAnyClientCallUpdater(this);
67
120
  break;
68
- case 'onAnyClientUpdate':
69
- this.callUpdater = new OnAnyClientCallUpdater(this);
121
+ case 'update-on-interval':
122
+ if (!settings.updateIntervalInMs) {
123
+ throw new Error('updateIntervalInMs setting in config must be set if updatePolicy is update-on-interval');
124
+ }
125
+ this.updater = new OnIntervalUpdater(
126
+ settings.updateIntervalInMs,
127
+ this.update.bind(this),
128
+ );
70
129
  break;
71
130
  }
72
131
 
@@ -74,6 +133,17 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
74
133
  case 'mediasoup-sfu':
75
134
  break;
76
135
  }
136
+
137
+ this._callStartedEvent = {
138
+ emitted: false,
139
+ };
140
+ this._callEndedEvent = {
141
+ emitted: false,
142
+ };
143
+ }
144
+
145
+ public get numberOfClients() {
146
+ return this.observedClients.size;
77
147
  }
78
148
 
79
149
  public get score() {
@@ -82,10 +152,14 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
82
152
 
83
153
  public close() {
84
154
  if (this.closed) return;
155
+ this.update(); // last update before closing
85
156
  this.closed = true;
86
157
 
158
+ this.updater?.close();
159
+
87
160
  [ ...this.observedClients.values() ].forEach((client) => client.close());
88
161
 
162
+ this.closedAt = Date.now();
89
163
  this.emit('close');
90
164
  }
91
165
 
@@ -101,19 +175,28 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
101
175
 
102
176
  const result = new ObservedClient<ClientAppData>(settings, this);
103
177
  const wasEmpty = this.observedClients.size === 0;
104
- const onUpdate = () => this.callUpdater?.onClientUpdate(result);
178
+ const onUpdate = () => this._onClientUpdate(result);
179
+ const joined = () => this._clientJoined(result);
180
+ const left = () => this._clientLeft(result);
105
181
 
106
182
  result.once('close', () => {
107
183
  result.off('update', onUpdate);
184
+ result.off('joined', joined);
185
+ result.off('left', left);
108
186
  this.observedClients.delete(settings.clientId);
109
187
 
110
188
  if (this.observedClients.size === 0) {
111
189
  this.emit('empty');
112
190
  }
191
+ ++this.totalRemovedClients;
113
192
  });
114
193
  result.on('update', onUpdate);
194
+ result.on('joined', joined);
195
+ result.on('left', left);
196
+ ++this.totalAddedClients;
115
197
 
116
198
  this.observedClients.set(settings.clientId, result);
199
+ this.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);
117
200
 
118
201
  this.emit('newclient', result);
119
202
 
@@ -124,10 +207,121 @@ export class ObservedCall<AppData extends Record<string, unknown> = Record<strin
124
207
  return result;
125
208
  }
126
209
 
210
+ public createEventMonitor<CTX>(context: CTX): ObservedCallEventMonitor<CTX> {
211
+ return new ObservedCallEventMonitor(this, context);
212
+ }
213
+
127
214
  public update() {
215
+ if (this.closed) return;
216
+
217
+ this.numberOfInboundRtpStreams = 0;
218
+ this.numberOfOutboundRtpStreams = 0;
219
+ this.numberOfPeerConnections = 0;
220
+ this.numberOfDataChannels = 0;
221
+
222
+ for (const client of this.observedClients.values()) {
223
+ this.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;
224
+ this.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;
225
+ this.numberOfPeerConnections += client.numberOfPeerConnections;
226
+ this.numberOfDataChannels += client.numberOfDataChannels;
227
+ }
228
+
128
229
  this.detectors.update();
129
230
  this.scoreCalculator.update();
130
231
 
131
232
  this.emit('update');
233
+
234
+ this.deltaNumberOfIssues = 0;
235
+ this.deltaRttLt50Measurements = 0;
236
+ this.deltaRttLt150Measurements = 0;
237
+ this.deltaRttLt300Measurements = 0;
238
+ this.deltaRttGtOrEq300Measurements = 0;
132
239
  }
240
+
241
+ private _onClientUpdate(client: ObservedClient) {
242
+ this.totalClientsReceivedAudioBytes += client.deltaReceivedAudioBytes;
243
+ this.totalClientsReceivedVideoBytes += client.deltaReceivedVideoBytes;
244
+ this.totalClientsReceivedDataChannelBytes += client.deltaDataChannelBytesReceived;
245
+ this.totalClientsReceivedBytes += client.deltaTransportReceivedBytes;
246
+ this.totalClientsSentAudioBytes += client.deltaSentAudioBytes;
247
+ this.totalClientsSentVideoBytes += client.deltaSentVideoBytes;
248
+ this.totalClientsSentDataChannelBytes += client.deltaDataChannelBytesSent;
249
+ this.totalClientsSentBytes += client.deltaTransportSentBytes;
250
+
251
+ this.deltaRttLt50Measurements += client.deltaRttLt50Measurements;
252
+ this.deltaRttLt150Measurements += client.deltaRttLt150Measurements;
253
+ this.deltaRttLt300Measurements += client.deltaRttLt300Measurements;
254
+ this.deltaRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
255
+
256
+ this.totalRttLt50Measurements += client.deltaRttLt50Measurements;
257
+ this.totalRttLt150Measurements += client.deltaRttLt150Measurements;
258
+ this.totalRttLt300Measurements += client.deltaRttLt300Measurements;
259
+ this.totalRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
260
+
261
+ this.deltaNumberOfIssues += client.deltaNumberOfIssues;
262
+ this.numberOfIssues += client.deltaNumberOfIssues;
263
+
264
+ if (client.usingTURN) {
265
+ this.clientsUsedTurn.add(client.clientId);
266
+ }
267
+ }
268
+
269
+ private _clientJoined(client: ObservedClient) {
270
+ if (!client.joinedAt) return;
271
+
272
+ this.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);
273
+ }
274
+
275
+ private _clientLeft(client: ObservedClient) {
276
+ if (!client.leftAt) return;
277
+
278
+ this.endedAt = Math.max(this.endedAt ?? client.leftAt, client.leftAt);
279
+ }
280
+
281
+ // public resetSummaryMetrics() {
282
+ // this.totalAddedClients = 0;
283
+ // this.totalRemovedClients = 0;
284
+
285
+ // this.totalClientsReceivedAudioBytes = 0;
286
+ // this.totalClientsReceivedVideoBytes = 0;
287
+ // this.totalClientsReceivedBytes = 0;
288
+
289
+ // this.totalClientsSentAudioBytes = 0;
290
+ // this.totalClientsSentVideoBytes = 0;
291
+ // this.totalClientsSentBytes = 0;
292
+
293
+ // this.totalRttLt50Measurements = 0;
294
+ // this.totalRttLt150Measurements = 0;
295
+ // this.totalRttLt300Measurements = 0;
296
+ // this.totalRttGtOrEq300Measurements = 0;
297
+
298
+ // this.numberOfIssues = 0;
299
+
300
+ // this.clientsUsedTurn.clear();
301
+
302
+ // }
303
+
304
+ // public createSummary(): ObservedCallSummary {
305
+ // return {
306
+ // currentActiveClients: this.observedClients.size,
307
+ // totalAddedClients: this.totalAddedClients,
308
+ // totalRemovedClients: this.totalRemovedClients,
309
+
310
+ // totalClientsReceivedAudioBytes: this.totalClientsReceivedBytes,
311
+ // totalClientsReceivedVideoBytes: this.totalClientsReceivedVideoBytes,
312
+ // totalClientsReceivedBytes: this.totalClientsReceivedBytes,
313
+
314
+ // totalClientsSentAudioBytes: this.totalClientsSentAudioBytes,
315
+ // totalClientsSentVideoBytes: this.totalClientsSentVideoBytes,
316
+ // totalClientsSentBytes: this.totalClientsSentBytes,
317
+
318
+ // totalRttLt50Measurements: this.totalRttLt50Measurements,
319
+ // totalRttLt150Measurements: this.totalRttLt150Measurements,
320
+ // totalRttLt300Measurements: this.totalRttLt300Measurements,
321
+ // totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
322
+
323
+ // numberOfIssues: this.numberOfIssues,
324
+ // numberOfClientsUsedTurn: this.clientsUsedTurn.size,
325
+ // };
326
+ // }
133
327
  }