@observertc/observer-js 0.42.9 → 1.0.1-28c6425.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 (279) hide show
  1. package/.prettierrc +6 -6
  2. package/README.md +0 -104
  3. package/lib/ObservedCall.d.ts +66 -42
  4. package/lib/ObservedCall.d.ts.map +1 -1
  5. package/lib/ObservedCall.js +232 -108
  6. package/lib/ObservedCallSummary.d.ts +18 -0
  7. package/lib/ObservedCallSummary.d.ts.map +1 -0
  8. package/lib/ObservedCertificate.d.ts +19 -0
  9. package/lib/ObservedCertificate.d.ts.map +1 -0
  10. package/lib/ObservedCertificate.js +38 -0
  11. package/lib/ObservedClient.d.ts +71 -130
  12. package/lib/ObservedClient.d.ts.map +1 -1
  13. package/lib/ObservedClient.js +311 -750
  14. package/lib/ObservedClientSummary.d.ts +23 -0
  15. package/lib/ObservedClientSummary.d.ts.map +1 -0
  16. package/lib/ObservedClientSummary.js +2 -0
  17. package/lib/ObservedCodec.d.ts +22 -0
  18. package/lib/ObservedCodec.d.ts.map +1 -0
  19. package/lib/ObservedCodec.js +45 -0
  20. package/lib/ObservedDataChannel.d.ts +23 -69
  21. package/lib/ObservedDataChannel.d.ts.map +1 -1
  22. package/lib/ObservedDataChannel.js +67 -109
  23. package/lib/ObservedIceCandidate.d.ts +29 -0
  24. package/lib/ObservedIceCandidate.d.ts.map +1 -0
  25. package/lib/ObservedIceCandidate.js +59 -0
  26. package/lib/ObservedIceCandidatePair.d.ts +44 -0
  27. package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
  28. package/lib/ObservedIceCandidatePair.js +111 -0
  29. package/lib/ObservedIceTransport.d.ts +36 -0
  30. package/lib/ObservedIceTransport.d.ts.map +1 -0
  31. package/lib/ObservedIceTransport.js +93 -0
  32. package/lib/ObservedInboundRtp.d.ts +92 -0
  33. package/lib/ObservedInboundRtp.d.ts.map +1 -0
  34. package/lib/ObservedInboundRtp.js +193 -0
  35. package/lib/ObservedInboundTrack.d.ts +29 -0
  36. package/lib/ObservedInboundTrack.d.ts.map +1 -0
  37. package/lib/ObservedInboundTrack.js +57 -0
  38. package/lib/ObservedMediaPlayout.d.ts +22 -0
  39. package/lib/ObservedMediaPlayout.d.ts.map +1 -0
  40. package/lib/ObservedMediaPlayout.js +42 -0
  41. package/lib/ObservedMediaSource.d.ts +28 -0
  42. package/lib/ObservedMediaSource.d.ts.map +1 -0
  43. package/lib/ObservedMediaSource.js +55 -0
  44. package/lib/ObservedOutboundRtp.d.ts +62 -0
  45. package/lib/ObservedOutboundRtp.d.ts.map +1 -0
  46. package/lib/ObservedOutboundRtp.js +144 -0
  47. package/lib/ObservedOutboundTrack.d.ts +29 -0
  48. package/lib/ObservedOutboundTrack.d.ts.map +1 -0
  49. package/lib/ObservedOutboundTrack.js +57 -0
  50. package/lib/ObservedPeerConnection.d.ts +132 -80
  51. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  52. package/lib/ObservedPeerConnection.js +630 -357
  53. package/lib/ObservedPeerConnectionTransport.d.ts +17 -0
  54. package/lib/ObservedPeerConnectionTransport.d.ts.map +1 -0
  55. package/lib/ObservedPeerConnectionTransport.js +34 -0
  56. package/lib/ObservedRemoteInboundRtp.d.ts +30 -0
  57. package/lib/ObservedRemoteInboundRtp.d.ts.map +1 -0
  58. package/lib/ObservedRemoteInboundRtp.js +60 -0
  59. package/lib/ObservedRemoteOutboundRtp.d.ts +30 -0
  60. package/lib/ObservedRemoteOutboundRtp.d.ts.map +1 -0
  61. package/lib/ObservedRemoteOutboundRtp.js +60 -0
  62. package/lib/ObservedTURN.d.ts +31 -0
  63. package/lib/ObservedTURN.d.ts.map +1 -0
  64. package/lib/ObservedTURN.js +58 -0
  65. package/lib/ObservedTurnServer.d.ts +25 -0
  66. package/lib/ObservedTurnServer.d.ts.map +1 -0
  67. package/lib/ObservedTurnServer.js +59 -0
  68. package/lib/Observer.d.ts +45 -51
  69. package/lib/Observer.d.ts.map +1 -1
  70. package/lib/Observer.js +150 -226
  71. package/lib/ObserverSummary.d.ts +13 -0
  72. package/lib/ObserverSummary.d.ts.map +1 -0
  73. package/lib/ObserverSummary.js +2 -0
  74. package/lib/common/Middleware.d.ts +10 -1
  75. package/lib/common/Middleware.d.ts.map +1 -1
  76. package/lib/common/Middleware.js +55 -36
  77. package/lib/common/logger.d.ts +8 -4
  78. package/lib/common/logger.d.ts.map +1 -1
  79. package/lib/common/logger.js +44 -68
  80. package/lib/common/types.d.ts +0 -21
  81. package/lib/common/types.d.ts.map +1 -1
  82. package/lib/common/types.js +1 -0
  83. package/lib/common/utils.d.ts +2 -1
  84. package/lib/common/utils.d.ts.map +1 -1
  85. package/lib/common/utils.js +17 -3
  86. package/lib/detectors/Detector.d.ts +5 -0
  87. package/lib/detectors/Detector.d.ts.map +1 -0
  88. package/lib/detectors/Detector.js +3 -0
  89. package/lib/detectors/Detectors.d.ts +11 -0
  90. package/lib/detectors/Detectors.d.ts.map +1 -0
  91. package/lib/detectors/Detectors.js +34 -0
  92. package/lib/index.d.ts +24 -25
  93. package/lib/index.d.ts.map +1 -1
  94. package/lib/index.js +41 -41
  95. package/lib/monitors/TurnUsageMonitor.d.ts +0 -52
  96. package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -1
  97. package/lib/monitors/TurnUsageMonitor.js +145 -120
  98. package/lib/schema/ClientEventTypes.d.ts +100 -0
  99. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  100. package/lib/schema/ClientEventTypes.js +38 -0
  101. package/lib/schema/ClientMetaTypes.d.ts +34 -0
  102. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  103. package/lib/schema/ClientMetaTypes.js +16 -0
  104. package/lib/schema/ClientSample.d.ts +1333 -0
  105. package/lib/schema/ClientSample.d.ts.map +1 -0
  106. package/lib/schema/ClientSample.js +4 -0
  107. package/lib/scores/CalculatedScore.d.ts +6 -0
  108. package/lib/scores/CalculatedScore.d.ts.map +1 -0
  109. package/lib/scores/CalculatedScore.js +2 -0
  110. package/lib/scores/DefaultCallScoreCalculator.d.ts +7 -0
  111. package/lib/scores/DefaultCallScoreCalculator.d.ts.map +1 -0
  112. package/lib/scores/DefaultCallScoreCalculator.js +21 -0
  113. package/lib/scores/ScoreCalculator.d.ts +4 -0
  114. package/lib/scores/ScoreCalculator.d.ts.map +1 -0
  115. package/lib/scores/ScoreCalculator.js +2 -0
  116. package/lib/updaters/CallUpdater.d.ts +5 -0
  117. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  118. package/lib/updaters/CallUpdater.js +2 -0
  119. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  120. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  121. package/lib/updaters/ObserverUpdater.js +2 -0
  122. package/lib/updaters/OnAllCallObserverUpdater_.d.ts +13 -0
  123. package/lib/updaters/OnAllCallObserverUpdater_.d.ts.map +1 -0
  124. package/lib/updaters/OnAllCallObserverUpdater_.js +38 -0
  125. package/lib/updaters/OnAllClientCallUpdater.d.ts +13 -0
  126. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  127. package/lib/updaters/OnAllClientCallUpdater.js +37 -0
  128. package/lib/updaters/OnAnyCallObserverUpdater_.d.ts +11 -0
  129. package/lib/updaters/OnAnyCallObserverUpdater_.d.ts.map +1 -0
  130. package/lib/updaters/OnAnyCallObserverUpdater_.js +27 -0
  131. package/lib/updaters/OnAnyClientCallUpdater.d.ts +11 -0
  132. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  133. package/lib/updaters/OnAnyClientCallUpdater.js +27 -0
  134. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  135. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  136. package/lib/updaters/OnIntervalUpdater.js +17 -0
  137. package/lib/updaters/Updater.d.ts +6 -0
  138. package/lib/updaters/Updater.d.ts.map +1 -0
  139. package/lib/updaters/Updater.js +2 -0
  140. package/lib/utils/RemoteTrackResolver.d.ts +7 -0
  141. package/lib/utils/RemoteTrackResolver.d.ts.map +1 -0
  142. package/lib/utils/RemoteTrackResolver.js +2 -0
  143. package/package.json +4 -4
  144. package/src/ObservedCall.ts +291 -164
  145. package/src/ObservedCallSummary.ts +22 -0
  146. package/src/ObservedCertificate.ts +43 -0
  147. package/src/ObservedClient.ts +342 -1064
  148. package/src/ObservedClientSummary.ts +24 -0
  149. package/src/ObservedCodec.ts +49 -0
  150. package/src/ObservedDataChannel.ts +68 -181
  151. package/src/ObservedIceCandidate.ts +64 -0
  152. package/src/ObservedIceCandidatePair.ts +118 -0
  153. package/src/ObservedIceTransport.ts +99 -0
  154. package/src/ObservedInboundRtp.ts +205 -0
  155. package/src/ObservedInboundTrack.ts +70 -0
  156. package/src/ObservedMediaPlayout.ts +49 -0
  157. package/src/ObservedMediaSource.ts +60 -0
  158. package/src/ObservedOutboundRtp.ts +156 -0
  159. package/src/ObservedOutboundTrack.ts +69 -0
  160. package/src/ObservedPeerConnection.ts +839 -408
  161. package/src/ObservedPeerConnectionTransport.ts +38 -0
  162. package/src/ObservedRemoteInboundRtp.ts +64 -0
  163. package/src/ObservedRemoteOutboundRtp.ts +65 -0
  164. package/src/ObservedTURN.ts +86 -0
  165. package/src/ObservedTurnServer.ts +72 -0
  166. package/src/Observer.ts +171 -294
  167. package/src/ObserverSummary.ts +15 -0
  168. package/src/common/Middleware.ts +70 -42
  169. package/src/common/logger.ts +60 -69
  170. package/src/common/types.ts +0 -42
  171. package/src/common/utils.ts +18 -2
  172. package/src/detectors/Detector.ts +6 -0
  173. package/src/detectors/Detectors.ts +38 -0
  174. package/src/index.ts +24 -90
  175. package/src/monitors/TurnUsageMonitor.ts +164 -164
  176. package/src/schema/ClientEventTypes.ts +112 -0
  177. package/src/schema/ClientMetaTypes.ts +41 -0
  178. package/src/schema/ClientSample.ts +1682 -0
  179. package/src/scores/CalculatedScore.ts +6 -0
  180. package/src/scores/DefaultCallScoreCalculator.ts +23 -0
  181. package/src/scores/ScoreCalculator.ts +3 -0
  182. package/src/updaters/CallUpdater.ts +5 -0
  183. package/src/updaters/ObserverUpdater.ts +5 -0
  184. package/src/updaters/OnAllCallObserverUpdater_.ts +46 -0
  185. package/src/updaters/OnAllClientCallUpdater.ts +46 -0
  186. package/src/updaters/OnAnyCallObserverUpdater_.ts +32 -0
  187. package/src/updaters/OnAnyClientCallUpdater.ts +32 -0
  188. package/src/updaters/OnIntervalUpdater.ts +19 -0
  189. package/src/updaters/Updater.ts +5 -0
  190. package/src/utils/RemoteTrackResolver.ts +12 -0
  191. package/tsconfig.json +3 -3
  192. package/lib/ObservedICE.d.ts +0 -64
  193. package/lib/ObservedICE.d.ts.map +0 -1
  194. package/lib/ObservedICE.js +0 -141
  195. package/lib/ObservedInboundAudioTrack.d.ts +0 -96
  196. package/lib/ObservedInboundAudioTrack.d.ts.map +0 -1
  197. package/lib/ObservedInboundAudioTrack.js +0 -217
  198. package/lib/ObservedInboundVideoTrack.d.ts +0 -101
  199. package/lib/ObservedInboundVideoTrack.d.ts.map +0 -1
  200. package/lib/ObservedInboundVideoTrack.js +0 -232
  201. package/lib/ObservedOutboundAudioTrack.d.ts +0 -87
  202. package/lib/ObservedOutboundAudioTrack.d.ts.map +0 -1
  203. package/lib/ObservedOutboundAudioTrack.js +0 -186
  204. package/lib/ObservedOutboundVideoTrack.d.ts +0 -91
  205. package/lib/ObservedOutboundVideoTrack.d.ts.map +0 -1
  206. package/lib/ObservedOutboundVideoTrack.js +0 -193
  207. package/lib/ObservedSfu.d.ts +0 -59
  208. package/lib/ObservedSfu.d.ts.map +0 -1
  209. package/lib/ObservedSfu.js +0 -157
  210. package/lib/ObservedSfuInboundRtpPad.d.ts +0 -42
  211. package/lib/ObservedSfuInboundRtpPad.d.ts.map +0 -1
  212. package/lib/ObservedSfuInboundRtpPad.js +0 -71
  213. package/lib/ObservedSfuOutboundRtpPad.d.ts +0 -42
  214. package/lib/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
  215. package/lib/ObservedSfuOutboundRtpPad.js +0 -72
  216. package/lib/ObservedSfuSctpChannel.d.ts +0 -42
  217. package/lib/ObservedSfuSctpChannel.d.ts.map +0 -1
  218. package/lib/ObservedSfuSctpChannel.js +0 -57
  219. package/lib/ObservedSfuTransport.d.ts +0 -58
  220. package/lib/ObservedSfuTransport.d.ts.map +0 -1
  221. package/lib/ObservedSfuTransport.js +0 -120
  222. package/lib/RemoteTrackAssigner.d.ts +0 -14
  223. package/lib/RemoteTrackAssigner.d.ts.map +0 -1
  224. package/lib/RemoteTrackAssigner.js +0 -52
  225. package/lib/ReportsCollector.d.ts +0 -109
  226. package/lib/ReportsCollector.d.ts.map +0 -1
  227. package/lib/ReportsCollector.js +0 -207
  228. package/lib/common/CalculatedScore.d.ts +0 -80
  229. package/lib/common/CalculatedScore.d.ts.map +0 -1
  230. package/lib/common/CalculatedScore.js +0 -162
  231. package/lib/common/CallEventType.d.ts +0 -63
  232. package/lib/common/CallEventType.d.ts.map +0 -1
  233. package/lib/common/CallEventType.js +0 -39
  234. package/lib/common/CallMetaReports.d.ts +0 -42
  235. package/lib/common/CallMetaReports.d.ts.map +0 -1
  236. package/lib/common/CallMetaReports.js +0 -36
  237. package/lib/common/QualityScoreUtils.d.ts +0 -1
  238. package/lib/common/QualityScoreUtils.d.ts.map +0 -1
  239. package/lib/common/QualityScoreUtils.js +0 -1
  240. package/lib/common/TypedEventEmitter.d.ts +0 -22
  241. package/lib/common/TypedEventEmitter.d.ts.map +0 -1
  242. package/lib/common/TypedEventEmitter.js +0 -11
  243. package/lib/common/callEventReports.d.ts +0 -10
  244. package/lib/common/callEventReports.d.ts.map +0 -1
  245. package/lib/common/callEventReports.js +0 -112
  246. package/lib/monitors/CallSummary.d.ts +0 -37
  247. package/lib/monitors/CallSummary.d.ts.map +0 -1
  248. package/lib/monitors/CallSummaryMonitor.d.ts +0 -32
  249. package/lib/monitors/CallSummaryMonitor.d.ts.map +0 -1
  250. package/lib/monitors/CallSummaryMonitor.js +0 -152
  251. package/lib/monitors/ClientIssueMonitor.d.ts +0 -32
  252. package/lib/monitors/ClientIssueMonitor.d.ts.map +0 -1
  253. package/lib/monitors/ClientIssueMonitor.js +0 -49
  254. package/lib/monitors/SfuServerMonitor.d.ts +0 -79
  255. package/lib/monitors/SfuServerMonitor.d.ts.map +0 -1
  256. package/lib/monitors/SfuServerMonitor.js +0 -198
  257. package/src/ObservedICE.ts +0 -237
  258. package/src/ObservedInboundAudioTrack.ts +0 -344
  259. package/src/ObservedInboundVideoTrack.ts +0 -361
  260. package/src/ObservedOutboundAudioTrack.ts +0 -307
  261. package/src/ObservedOutboundVideoTrack.ts +0 -319
  262. package/src/ObservedSfu.ts +0 -231
  263. package/src/ObservedSfuInboundRtpPad.ts +0 -106
  264. package/src/ObservedSfuOutboundRtpPad.ts +0 -107
  265. package/src/ObservedSfuSctpChannel.ts +0 -103
  266. package/src/ObservedSfuTransport.ts +0 -185
  267. package/src/RemoteTrackAssigner.ts +0 -68
  268. package/src/ReportsCollector.ts +0 -336
  269. package/src/common/CalculatedScore.ts +0 -188
  270. package/src/common/CallEventType.ts +0 -69
  271. package/src/common/CallMetaReports.ts +0 -82
  272. package/src/common/QualityScoreUtils.ts +0 -0
  273. package/src/common/TypedEventEmitter.ts +0 -32
  274. package/src/common/callEventReports.ts +0 -178
  275. package/src/monitors/CallSummary.ts +0 -38
  276. package/src/monitors/CallSummaryMonitor.ts +0 -192
  277. package/src/monitors/ClientIssueMonitor.ts +0 -88
  278. package/src/monitors/SfuServerMonitor.ts +0 -285
  279. /package/lib/{monitors/CallSummary.js → ObservedCallSummary.js} +0 -0
@@ -1,27 +1,33 @@
1
1
  import { EventEmitter } from 'events';
2
- import { ObservedClient, ObservedClientModel } from './ObservedClient';
2
+ import { ObservedClient, ObservedClientSettings } from './ObservedClient';
3
3
  import { Observer } from './Observer';
4
- import { createClientJoinedEventReport, createClientLeftEventReport } from './common/callEventReports';
5
- import { getMedian, PartialBy } from './common/utils';
6
- import { CallEventReport } from '@observertc/report-schemas-js';
7
- import { createProcessor } from './common/Middleware';
8
- import { ClientSample } from '@observertc/sample-schemas-js';
9
- import { ObservedOutboundAudioTrack } from './ObservedOutboundAudioTrack';
10
- import { ObservedOutboundVideoTrack } from './ObservedOutboundVideoTrack';
11
- import { CalculatedScore } from './common/CalculatedScore';
12
-
13
- export type ObservedCallModel = {
14
- serviceId: string;
15
- roomId: string;
4
+ import { ScoreCalculator } from './scores/ScoreCalculator';
5
+ import { CalculatedScore } from './scores/CalculatedScore';
6
+ import { DefaultCallScoreCalculator } from './scores/DefaultCallScoreCalculator';
7
+ import { Detectors } from './detectors/Detectors';
8
+ import { RemoteTrackResolver } from './utils/RemoteTrackResolver';
9
+ import { OnAllClientCallUpdater } from './updaters/OnAllClientCallUpdater';
10
+ import { Updater } from './updaters/Updater';
11
+ import { OnIntervalUpdater } from './updaters/OnIntervalUpdater';
12
+ import { ObservedCallSummary } from './ObservedCallSummary';
13
+ import { OnAnyClientCallUpdater } from './updaters/OnAnyClientCallUpdater';
14
+
15
+ export type ObservedCallSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
16
16
  callId: string;
17
+ appData?: AppData;
18
+ remoteTrackResolvePolicy?: 'p2p' | 'mediasoup-sfu',
19
+ updatePolicy?: 'update-on-any-client-updated' | 'update-when-all-client-updated' | 'update-on-interval',
20
+ updateIntervalInMs?: number,
17
21
  };
18
22
 
19
23
  export type ObservedCallEvents = {
20
24
  update: [],
21
25
  newclient: [ObservedClient],
22
- callevent: [Omit<CallEventReport, 'callId' | 'serviceId' | 'roomId'>],
23
26
  empty: [],
27
+ 'not-empty': [],
24
28
  close: [],
29
+ started: [],
30
+ ended: [],
25
31
  }
26
32
 
27
33
  export declare interface ObservedCall {
@@ -32,195 +38,316 @@ export declare interface ObservedCall {
32
38
  }
33
39
 
34
40
  export class ObservedCall<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
35
- public readonly created = Date.now();
36
-
37
- public readonly processor = createProcessor<ClientSample>();
38
-
39
- private readonly _clients = new Map<string, ObservedClient>();
40
-
41
- public _scoreData?: {
42
- score: CalculatedScore,
43
- calculated: number,
41
+ public readonly detectors: Detectors;
42
+ public updater?: Updater;
43
+ public scoreCalculator: ScoreCalculator;
44
+ public readonly callId: string;
45
+ public readonly observedClients = new Map<string, ObservedClient>();
46
+ public readonly clientsUsedTurn = new Set<string>();
47
+ public readonly calculatedScore: CalculatedScore = {
48
+ weight: 1,
49
+ value: undefined,
44
50
  };
45
-
46
- public readonly sfuStreamIdToOutboundAudioTrack = new Map<string | number, ObservedOutboundAudioTrack>();
47
- public readonly sfuStreamIdToOutboundVideoTrack = new Map<string | number, ObservedOutboundVideoTrack>();
48
- private _closed = false;
49
- // this changes as clients emitting their joined event, as the call starts when the first client joins
50
- public started?: number;
51
- // this changes as clients emitting their left event, as the call ends when the last client leaves
51
+ public remoteTrackResolver?: RemoteTrackResolver;
52
+
53
+ public totalAddedClients = 0;
54
+ public totalRemovedClients = 0;
55
+
56
+ public totalClientsReceivedAudioBytes = 0;
57
+ public totalClientsReceivedVideoBytes = 0;
58
+ public totalClientsReceivedDataChannelBytes = 0;
59
+ public totalClientsReceivedBytes = 0;
60
+
61
+ public totalClientsSentAudioBytes = 0;
62
+ public totalClientsSentDataChannelBytes = 0;
63
+ public totalClientsSentVideoBytes = 0;
64
+ public totalClientsSentBytes = 0;
65
+
66
+ public totalRttLt50Measurements = 0;
67
+ public totalRttLt150Measurements = 0;
68
+ public totalRttLt300Measurements = 0;
69
+ public totalRttGtOrEq300Measurements = 0;
70
+
71
+ public numberOfIssues = 0;
72
+ public numberOfPeerConnections = 0;
73
+ public numberOfInboundRtpStreams = 0;
74
+ public numberOfOutboundRtpStreams = 0;
75
+ public numberOfDataChannels = 0;
76
+
77
+ public maxNumberOfClients = 0;
78
+ public deltaNumberOfIssues = 0;
79
+
80
+ public deltaRttLt50Measurements = 0;
81
+ public deltaRttLt150Measurements = 0;
82
+ public deltaRttLt300Measurements = 0;
83
+ public deltaRttGtOrEq300Measurements = 0;
84
+
85
+ public appData: AppData;
86
+ public closed = false;
87
+ public startedAt?: number;
52
88
  public ended?: number;
53
89
 
54
- public observationUpdated = Date.now();
55
- public observationEnded?: number;
56
- public readonly observationStarted = Date.now();
90
+ private _callStartedEvent: {
91
+ emitted: boolean,
92
+ timer?: ReturnType<typeof setTimeout>,
93
+ };
94
+ private _callEndedEvent: {
95
+ emitted: boolean
96
+ };
57
97
 
58
98
  public constructor(
59
- private readonly _model: ObservedCallModel,
99
+ settings: ObservedCallSettings<AppData>,
60
100
  public readonly observer: Observer,
61
- public readonly appData: AppData,
62
101
  ) {
63
102
  super();
64
103
  this.setMaxListeners(Infinity);
104
+
105
+ this.callId = settings.callId;
106
+ this.appData = settings.appData ?? {} as AppData;
107
+ this.scoreCalculator = new DefaultCallScoreCalculator(this);
108
+ this.detectors = new Detectors();
109
+
110
+ if (settings.updateIntervalInMs) {
111
+ if (settings.updatePolicy !== 'update-on-interval') {
112
+ throw new Error('updatePolicy must be update-on-interval if updateIntervalInMs is set in config');
113
+ }
114
+ }
115
+ switch (settings.updatePolicy) {
116
+ case 'update-on-any-client-updated':
117
+ this.updater = new OnAllClientCallUpdater(this);
118
+ break;
119
+ case 'update-when-all-client-updated':
120
+ this.updater = new OnAnyClientCallUpdater(this);
121
+ break;
122
+ case 'update-on-interval':
123
+ if (!settings.updateIntervalInMs) {
124
+ throw new Error('updateIntervalInMs setting in config must be set if updatePolicy is update-on-interval');
125
+ }
126
+ this.updater = new OnIntervalUpdater(
127
+ settings.updateIntervalInMs,
128
+ this.update.bind(this),
129
+ );
130
+ break;
131
+ }
132
+
133
+ switch (settings.remoteTrackResolvePolicy) {
134
+ case 'mediasoup-sfu':
135
+ break;
136
+ }
137
+
138
+ this._callStartedEvent = {
139
+ emitted: false,
140
+ };
141
+ this._callEndedEvent = {
142
+ emitted: false,
143
+ };
65
144
  }
66
145
 
67
- public get serviceId(): string {
68
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
69
- return this._model.serviceId!;
146
+ public get numberOfClients() {
147
+ return this.observedClients.size;
70
148
  }
71
149
 
72
- public get reports() {
73
- return this.observer.reports;
150
+ public get score() {
151
+ return this.calculatedScore.value;
74
152
  }
75
153
 
76
- public get roomId() {
77
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
78
- return this._model.roomId!;
154
+ public close() {
155
+ if (this.closed) return;
156
+ this.closed = true;
157
+
158
+ this.updater?.close();
159
+
160
+ [ ...this.observedClients.values() ].forEach((client) => client.close());
161
+ // make sure to emit the events
162
+ this.emitCallStartedEvent();
163
+ this.emitCallEndedEvent();
164
+
165
+ this.emit('close');
79
166
  }
80
167
 
81
- public get callId() {
82
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
83
- return this._model.callId!;
168
+ public getObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(clientId: string): ObservedClient<ClientAppData> | undefined {
169
+ if (this.closed || !this.observedClients.has(clientId)) return;
170
+
171
+ return this.observedClients.get(clientId) as ObservedClient<ClientAppData>;
84
172
  }
85
173
 
86
- public get clients(): ReadonlyMap<string, ObservedClient> {
87
- return this._clients;
174
+ public createObservedClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(settings: ObservedClientSettings<ClientAppData>): ObservedClient<ClientAppData> {
175
+ if (this.closed) throw new Error(`Call ${this.callId} is closed`);
176
+ if (this.observedClients.has(settings.clientId)) throw new Error(`Client with id ${settings.clientId} already exists`);
177
+
178
+ const result = new ObservedClient<ClientAppData>(settings, this);
179
+ const wasEmpty = this.observedClients.size === 0;
180
+ const onUpdate = () => this._onClientUpdate(result);
181
+ const joined = () => this._clientJoined(result);
182
+ const left = () => this._clientLeft(result);
183
+
184
+ result.once('close', () => {
185
+ result.off('update', onUpdate);
186
+ result.off('joined', joined);
187
+ result.off('left', left);
188
+ this.observedClients.delete(settings.clientId);
189
+
190
+ if (this.observedClients.size === 0) {
191
+ this.emit('empty');
192
+ }
193
+ --this.totalRemovedClients;
194
+ });
195
+ result.on('update', onUpdate);
196
+ result.on('joined', joined);
197
+ result.on('left', left);
198
+ ++this.totalAddedClients;
199
+
200
+ this.observedClients.set(settings.clientId, result);
201
+ this.maxNumberOfClients = Math.max(this.maxNumberOfClients, this.observedClients.size);
202
+
203
+ this.emit('newclient', result);
204
+
205
+ if (wasEmpty) {
206
+ this.emit('not-empty');
207
+ }
208
+
209
+ return result;
88
210
  }
89
211
 
90
- public get score(): CalculatedScore | undefined {
91
- const now = Date.now();
92
-
93
- if (now - 15000 < (this._scoreData?.calculated ?? 0)) {
94
- return this._scoreData?.score;
95
- } else if (this.clients.size < 1) {
96
- return {
97
- remarks: [ {
98
- severity: 'none',
99
- text: 'No clients',
100
- } ],
101
- score: 5.0,
102
- timestamp: now,
103
- };
212
+ public update() {
213
+ if (this.closed) return;
214
+
215
+ this.numberOfInboundRtpStreams = 0;
216
+ this.numberOfOutboundRtpStreams = 0;
217
+ this.numberOfPeerConnections = 0;
218
+ this.numberOfDataChannels = 0;
219
+
220
+ for (const client of this.observedClients.values()) {
221
+ this.numberOfInboundRtpStreams += client.numberOfInboundRtpStreams;
222
+ this.numberOfOutboundRtpStreams += client.numberOfOutboundRtpStreams;
223
+ this.numberOfPeerConnections += client.numberOfPeerConnections;
224
+ this.numberOfDataChannels += client.numberOfDataChannels;
225
+
226
+ if (client.usingTURN) {
227
+ this.clientsUsedTurn.add(client.clientId);
228
+ }
104
229
  }
105
- const scores = [ ...this.clients.values() ].map((client) => client.score?.score ?? 5.0);
106
-
107
- this._scoreData = {
108
- score: {
109
- remarks: [],
110
- score: getMedian(scores),
111
- timestamp: now,
112
- },
113
- calculated: now,
114
- };
115
230
 
116
- return this._scoreData.score;
231
+ this.detectors.update();
232
+ this.scoreCalculator.update();
233
+
234
+ this.emit('update');
235
+
236
+ this.deltaNumberOfIssues = 0;
237
+ this.deltaRttLt50Measurements = 0;
238
+ this.deltaRttLt150Measurements = 0;
239
+ this.deltaRttLt300Measurements = 0;
240
+ this.deltaRttGtOrEq300Measurements = 0;
117
241
  }
118
242
 
119
- public get closed() {
120
- return this._closed;
243
+ private _onClientUpdate(client: ObservedClient) {
244
+ this.totalClientsReceivedAudioBytes += client.deltaReceivedAudioBytes;
245
+ this.totalClientsSentAudioBytes += client.deltaSentAudioBytes;
246
+ this.totalClientsReceivedVideoBytes += client.deltaReceivedVideoBytes;
247
+ this.totalClientsReceivedVideoBytes += client.deltaSentVideoBytes;
248
+ this.totalClientsReceivedDataChannelBytes += client.deltaDataChannelBytesReceived;
249
+ this.totalClientsSentDataChannelBytes += client.deltaDataChannelBytesSent;
250
+ this.totalClientsReceivedBytes += client.deltaTransportReceivedBytes;
251
+ this.totalClientsSentBytes += client.deltaTransportSentBytes;
252
+
253
+ this.deltaRttLt50Measurements += client.deltaRttLt50Measurements;
254
+ this.deltaRttLt150Measurements += client.deltaRttLt150Measurements;
255
+ this.deltaRttLt300Measurements += client.deltaRttLt300Measurements;
256
+ this.deltaRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
257
+
258
+ this.totalRttLt50Measurements += client.deltaRttLt50Measurements;
259
+ this.totalRttLt150Measurements += client.deltaRttLt150Measurements;
260
+ this.totalRttLt300Measurements += client.deltaRttLt300Measurements;
261
+ this.totalRttGtOrEq300Measurements += client.deltaRttGtOrEq300Measurements;
262
+
263
+ this.deltaNumberOfIssues += client.deltaNumberOfIssues;
264
+ this.numberOfIssues += client.deltaNumberOfIssues;
121
265
  }
122
266
 
123
- public close() {
124
- if (this._closed) return;
125
- this._closed = true;
267
+ private _clientJoined(client: ObservedClient) {
268
+ if (!client.joinedAt) return;
126
269
 
127
- Array.from(this._clients.values()).forEach((client) => client.close());
270
+ this.startedAt = Math.min(this.startedAt ?? client.joinedAt, client.joinedAt);
128
271
 
129
- this.observationEnded = Date.now();
130
-
131
- this.emit('close');
272
+ if (this._callStartedEvent.emitted) return;
273
+ if (this._callStartedEvent.timer) {
274
+ if (1 < this.observedClients.size) {
275
+ this.emitCallStartedEvent();
276
+ }
277
+
278
+ return;
279
+ }
280
+ this._callStartedEvent.timer = setTimeout(() => {
281
+ this.emitCallStartedEvent();
282
+ }, 5000);
132
283
  }
133
284
 
134
- public addEventReport(params: PartialBy<Omit<CallEventReport, 'serviceId' | 'roomId' | 'callId' >, 'timestamp'>) {
135
- this.reports.addCallEventReport({
136
- ...params,
137
- serviceId: this.serviceId,
138
- roomId: this.roomId,
139
- callId: this.callId,
140
- timestamp: params.timestamp ?? Date.now(),
141
- });
285
+ private _clientLeft(client: ObservedClient) {
286
+ if (!client.leftAt) return;
287
+
288
+ this.ended = Math.max(this.ended ?? client.leftAt, client.leftAt);
142
289
  }
143
290
 
144
- public createClient<ClientAppData extends Record<string, unknown> = Record<string, unknown>>(config: ObservedClientModel & {
145
- appData: ClientAppData,
146
- // in case we generate the CLIENT_JOINED report we can set the timestamp of the event
147
- // in that case we should set the client.left to the timestamp of the leaving.
148
- // by default the timestamp is set to the current time
149
- joinedTimestamp?: number,
150
- createClientJoinedReport?: boolean,
151
- createClientLeftReport?: boolean,
152
- }) {
153
- if (this._closed) throw new Error(`Call ${this.callId} is closed`);
154
-
155
- const {
156
- appData,
157
- createClientJoinedReport,
158
- createClientLeftReport,
159
- joinedTimestamp = Date.now(),
160
- ...model
161
- } = config;
162
-
163
- const result = new ObservedClient(model, this, appData);
164
- const onUpdate = ({ sample }: { sample: ClientSample }) => {
165
- this.observationUpdated = Date.now();
166
- if (result.joined) {
167
- if (this.started === undefined || result.joined < this.started) {
168
- this.started = result.joined;
169
- }
170
- }
171
- if (result.left) {
172
- if (this.ended === undefined || result.left > this.ended) {
173
- this.ended = result.left;
174
- }
175
- }
291
+ public emitCallStartedEvent() {
292
+ if (this._callStartedEvent.emitted) return;
293
+ this._callStartedEvent.emitted = true;
294
+ clearTimeout(this._callStartedEvent.timer);
295
+ this._callStartedEvent.timer = undefined;
176
296
 
177
- this.emit('update');
297
+ this.emit('started');
298
+ }
178
299
 
179
- this.processor.process(sample);
180
- };
300
+ public emitCallEndedEvent() {
301
+ if (this._callEndedEvent.emitted) return;
302
+ this._callEndedEvent.emitted = true;
181
303
 
182
- result.once('close', () => {
183
- result.off('update', onUpdate);
184
- this._clients.delete(result.clientId);
185
-
186
- if (this._clients.size === 0) {
187
- this.emit('empty');
188
- }
189
- });
304
+ this.emit('ended');
305
+ }
190
306
 
191
- result.on('update', onUpdate);
192
- this._clients.set(result.clientId, result);
193
-
194
- if (createClientJoinedReport) {
195
- this.reports.addCallEventReport(createClientJoinedEventReport(
196
- this.serviceId,
197
- result.mediaUnitId,
198
- this.roomId,
199
- this.callId,
200
- result.clientId,
201
- result.joined ?? joinedTimestamp,
202
- result.userId,
203
- result.marker,
204
- ));
205
- }
307
+ public resetSummaryMetrics() {
308
+ this.totalAddedClients = 0;
309
+ this.totalRemovedClients = 0;
206
310
 
207
- result.once('close', () => {
208
- if (createClientLeftReport) {
209
- this.reports.addCallEventReport(createClientLeftEventReport(
210
- this.serviceId,
211
- result.mediaUnitId,
212
- this.roomId,
213
- this.callId,
214
- result.clientId,
215
- result.left ?? Date.now(),
216
- result.userId,
217
- result.marker,
218
- ));
219
- }
220
- });
311
+ this.totalClientsReceivedAudioBytes = 0;
312
+ this.totalClientsReceivedVideoBytes = 0;
313
+ this.totalClientsReceivedBytes = 0;
221
314
 
222
- this.emit('newclient', result);
315
+ this.totalClientsSentAudioBytes = 0;
316
+ this.totalClientsSentVideoBytes = 0;
317
+ this.totalClientsSentBytes = 0;
318
+
319
+ this.totalRttLt50Measurements = 0;
320
+ this.totalRttLt150Measurements = 0;
321
+ this.totalRttLt300Measurements = 0;
322
+ this.totalRttGtOrEq300Measurements = 0;
323
+
324
+ this.numberOfIssues = 0;
325
+
326
+ this.clientsUsedTurn.clear();
223
327
 
224
- return result;
328
+ }
329
+
330
+ public createSummary(): ObservedCallSummary {
331
+ return {
332
+ currentActiveClients: this.observedClients.size,
333
+ totalAddedClients: this.totalAddedClients,
334
+ totalRemovedClients: this.totalRemovedClients,
335
+
336
+ totalClientsReceivedAudioBytes: this.totalClientsReceivedBytes,
337
+ totalClientsReceivedVideoBytes: this.totalClientsReceivedVideoBytes,
338
+ totalClientsReceivedBytes: this.totalClientsReceivedBytes,
339
+
340
+ totalClientsSentAudioBytes: this.totalClientsSentAudioBytes,
341
+ totalClientsSentVideoBytes: this.totalClientsSentVideoBytes,
342
+ totalClientsSentBytes: this.totalClientsSentBytes,
343
+
344
+ totalRttLt50Measurements: this.totalRttLt50Measurements,
345
+ totalRttLt150Measurements: this.totalRttLt150Measurements,
346
+ totalRttLt300Measurements: this.totalRttLt300Measurements,
347
+ totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
348
+
349
+ numberOfIssues: this.numberOfIssues,
350
+ numberOfClientsUsedTurn: this.clientsUsedTurn.size,
351
+ };
225
352
  }
226
353
  }
@@ -0,0 +1,22 @@
1
+ export type ObservedCallSummary = {
2
+ currentActiveClients: number;
3
+
4
+ totalAddedClients: number;
5
+ totalRemovedClients: number;
6
+
7
+ totalClientsSentBytes: number,
8
+ totalClientsReceivedBytes: number,
9
+ totalClientsReceivedAudioBytes: number,
10
+ totalClientsReceivedVideoBytes: number,
11
+ totalClientsSentAudioBytes: number,
12
+ totalClientsSentVideoBytes: number,
13
+
14
+ totalRttLt50Measurements: number,
15
+ totalRttLt150Measurements: number,
16
+ totalRttLt300Measurements: number,
17
+ totalRttGtOrEq300Measurements: number,
18
+
19
+ numberOfIssues: number,
20
+
21
+ numberOfClientsUsedTurn: number;
22
+ }
@@ -0,0 +1,43 @@
1
+ import { ObservedPeerConnection } from './ObservedPeerConnection';
2
+ import { CertificateStats } from './schema/ClientSample';
3
+
4
+ export class ObservedCertificate implements CertificateStats {
5
+ public appData?: Record<string, unknown>;
6
+
7
+ private _visited = false;
8
+
9
+ fingerprint?: string;
10
+ fingerprintAlgorithm?: string;
11
+ base64Certificate?: string;
12
+ issuerCertificateId?: string;
13
+ attachments?: Record<string, unknown>;
14
+
15
+ public constructor(
16
+ public timestamp: number,
17
+ public id: string,
18
+ private readonly _peerConnection: ObservedPeerConnection
19
+ ) {}
20
+
21
+ public get visited() {
22
+ const visited = this._visited;
23
+
24
+ this._visited = false;
25
+
26
+ return visited;
27
+ }
28
+
29
+ public getPeerConnection() {
30
+ return this._peerConnection;
31
+ }
32
+
33
+ public update(stats: CertificateStats) {
34
+ this._visited = true;
35
+
36
+ this.timestamp = stats.timestamp;
37
+ this.fingerprint = stats.fingerprint;
38
+ this.fingerprintAlgorithm = stats.fingerprintAlgorithm;
39
+ this.base64Certificate = stats.base64Certificate;
40
+ this.issuerCertificateId = stats.issuerCertificateId;
41
+ this.attachments = stats.attachments;
42
+ }
43
+ }