@observertc/observer-js 0.42.8 → 1.0.1-198a187.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 (295) hide show
  1. package/.prettierrc +6 -6
  2. package/README.md +0 -104
  3. package/lib/ObservedCall.d.ts +63 -43
  4. package/lib/ObservedCall.d.ts.map +1 -1
  5. package/lib/ObservedCall.js +188 -108
  6. package/lib/ObservedCallEventMonitor.d.ts +104 -0
  7. package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
  8. package/lib/ObservedCallEventMonitor.js +314 -0
  9. package/lib/ObservedCallSummary.d.ts +18 -0
  10. package/lib/ObservedCallSummary.d.ts.map +1 -0
  11. package/lib/ObservedCertificate.d.ts +19 -0
  12. package/lib/ObservedCertificate.d.ts.map +1 -0
  13. package/lib/ObservedCertificate.js +38 -0
  14. package/lib/ObservedClient.d.ts +80 -130
  15. package/lib/ObservedClient.d.ts.map +1 -1
  16. package/lib/ObservedClient.js +584 -744
  17. package/lib/ObservedClientEventMonitor.d.ts +89 -0
  18. package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
  19. package/lib/ObservedClientEventMonitor.js +247 -0
  20. package/lib/ObservedClientSummary.d.ts +23 -0
  21. package/lib/ObservedClientSummary.d.ts.map +1 -0
  22. package/lib/ObservedClientSummary.js +2 -0
  23. package/lib/ObservedCodec.d.ts +22 -0
  24. package/lib/ObservedCodec.d.ts.map +1 -0
  25. package/lib/ObservedCodec.js +45 -0
  26. package/lib/ObservedDataChannel.d.ts +25 -69
  27. package/lib/ObservedDataChannel.d.ts.map +1 -1
  28. package/lib/ObservedDataChannel.js +69 -109
  29. package/lib/ObservedIceCandidate.d.ts +29 -0
  30. package/lib/ObservedIceCandidate.d.ts.map +1 -0
  31. package/lib/ObservedIceCandidate.js +59 -0
  32. package/lib/ObservedIceCandidatePair.d.ts +45 -0
  33. package/lib/ObservedIceCandidatePair.d.ts.map +1 -0
  34. package/lib/ObservedIceCandidatePair.js +127 -0
  35. package/lib/ObservedIceTransport.d.ts +36 -0
  36. package/lib/ObservedIceTransport.d.ts.map +1 -0
  37. package/lib/ObservedIceTransport.js +93 -0
  38. package/lib/ObservedInboundRtp.d.ts +92 -0
  39. package/lib/ObservedInboundRtp.d.ts.map +1 -0
  40. package/lib/ObservedInboundRtp.js +193 -0
  41. package/lib/ObservedInboundTrack.d.ts +32 -0
  42. package/lib/ObservedInboundTrack.d.ts.map +1 -0
  43. package/lib/ObservedInboundTrack.js +60 -0
  44. package/lib/ObservedMediaPlayout.d.ts +22 -0
  45. package/lib/ObservedMediaPlayout.d.ts.map +1 -0
  46. package/lib/ObservedMediaPlayout.js +42 -0
  47. package/lib/ObservedMediaSource.d.ts +28 -0
  48. package/lib/ObservedMediaSource.d.ts.map +1 -0
  49. package/lib/ObservedMediaSource.js +55 -0
  50. package/lib/ObservedOutboundRtp.d.ts +62 -0
  51. package/lib/ObservedOutboundRtp.d.ts.map +1 -0
  52. package/lib/ObservedOutboundRtp.js +144 -0
  53. package/lib/ObservedOutboundTrack.d.ts +32 -0
  54. package/lib/ObservedOutboundTrack.d.ts.map +1 -0
  55. package/lib/ObservedOutboundTrack.js +60 -0
  56. package/lib/ObservedPeerConnection.d.ts +154 -80
  57. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  58. package/lib/ObservedPeerConnection.js +709 -357
  59. package/lib/ObservedPeerConnectionTransport.d.ts +17 -0
  60. package/lib/ObservedPeerConnectionTransport.d.ts.map +1 -0
  61. package/lib/ObservedPeerConnectionTransport.js +34 -0
  62. package/lib/ObservedRemoteInboundRtp.d.ts +30 -0
  63. package/lib/ObservedRemoteInboundRtp.d.ts.map +1 -0
  64. package/lib/ObservedRemoteInboundRtp.js +60 -0
  65. package/lib/ObservedRemoteOutboundRtp.d.ts +30 -0
  66. package/lib/ObservedRemoteOutboundRtp.d.ts.map +1 -0
  67. package/lib/ObservedRemoteOutboundRtp.js +60 -0
  68. package/lib/ObservedTURN.d.ts +31 -0
  69. package/lib/ObservedTURN.d.ts.map +1 -0
  70. package/lib/ObservedTURN.js +58 -0
  71. package/lib/ObservedTurnServer.d.ts +25 -0
  72. package/lib/ObservedTurnServer.d.ts.map +1 -0
  73. package/lib/ObservedTurnServer.js +59 -0
  74. package/lib/Observer.d.ts +49 -54
  75. package/lib/Observer.d.ts.map +1 -1
  76. package/lib/Observer.js +138 -225
  77. package/lib/ObserverEventMonitor.d.ts +138 -0
  78. package/lib/ObserverEventMonitor.d.ts.map +1 -0
  79. package/lib/ObserverEventMonitor.js +433 -0
  80. package/lib/ObserverSummary.d.ts +13 -0
  81. package/lib/ObserverSummary.d.ts.map +1 -0
  82. package/lib/ObserverSummary.js +2 -0
  83. package/lib/common/Middleware.d.ts +10 -1
  84. package/lib/common/Middleware.d.ts.map +1 -1
  85. package/lib/common/Middleware.js +55 -36
  86. package/lib/common/logger.d.ts +8 -4
  87. package/lib/common/logger.d.ts.map +1 -1
  88. package/lib/common/logger.js +44 -68
  89. package/lib/common/types.d.ts +0 -21
  90. package/lib/common/types.d.ts.map +1 -1
  91. package/lib/common/types.js +1 -0
  92. package/lib/common/utils.d.ts +3 -1
  93. package/lib/common/utils.d.ts.map +1 -1
  94. package/lib/common/utils.js +23 -3
  95. package/lib/detectors/Detector.d.ts +5 -0
  96. package/lib/detectors/Detector.d.ts.map +1 -0
  97. package/lib/detectors/Detector.js +3 -0
  98. package/lib/detectors/Detectors.d.ts +11 -0
  99. package/lib/detectors/Detectors.d.ts.map +1 -0
  100. package/lib/detectors/Detectors.js +34 -0
  101. package/lib/index.d.ts +26 -24
  102. package/lib/index.d.ts.map +1 -1
  103. package/lib/index.js +45 -41
  104. package/lib/monitors/TurnUsageMonitor.d.ts +0 -52
  105. package/lib/monitors/TurnUsageMonitor.d.ts.map +1 -1
  106. package/lib/monitors/TurnUsageMonitor.js +145 -120
  107. package/lib/schema/ClientEventTypes.d.ts +228 -0
  108. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  109. package/lib/schema/ClientEventTypes.js +41 -0
  110. package/lib/schema/ClientMetaTypes.d.ts +34 -0
  111. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  112. package/lib/schema/ClientMetaTypes.js +16 -0
  113. package/lib/schema/ClientSample.d.ts +1333 -0
  114. package/lib/schema/ClientSample.d.ts.map +1 -0
  115. package/lib/schema/ClientSample.js +4 -0
  116. package/lib/scores/CalculatedScore.d.ts +6 -0
  117. package/lib/scores/CalculatedScore.d.ts.map +1 -0
  118. package/lib/scores/CalculatedScore.js +2 -0
  119. package/lib/scores/DefaultCallScoreCalculator.d.ts +7 -0
  120. package/lib/scores/DefaultCallScoreCalculator.d.ts.map +1 -0
  121. package/lib/scores/DefaultCallScoreCalculator.js +21 -0
  122. package/lib/scores/ScoreCalculator.d.ts +4 -0
  123. package/lib/scores/ScoreCalculator.d.ts.map +1 -0
  124. package/lib/scores/ScoreCalculator.js +2 -0
  125. package/lib/updaters/CallUpdater.d.ts +5 -0
  126. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  127. package/lib/updaters/CallUpdater.js +2 -0
  128. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  129. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  130. package/lib/updaters/ObserverUpdater.js +2 -0
  131. package/lib/updaters/OnAllCallObserverUpdater.d.ts +15 -0
  132. package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
  133. package/lib/updaters/OnAllCallObserverUpdater.js +50 -0
  134. package/lib/updaters/OnAllClientCallUpdater.d.ts +15 -0
  135. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  136. package/lib/updaters/OnAllClientCallUpdater.js +53 -0
  137. package/lib/updaters/OnAnyCallObserverUpdater.d.ts +12 -0
  138. package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
  139. package/lib/updaters/OnAnyCallObserverUpdater.js +37 -0
  140. package/lib/updaters/OnAnyClientCallUpdater.d.ts +12 -0
  141. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  142. package/lib/updaters/OnAnyClientCallUpdater.js +36 -0
  143. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  144. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  145. package/lib/updaters/OnIntervalUpdater.js +17 -0
  146. package/lib/updaters/Updater.d.ts +6 -0
  147. package/lib/updaters/Updater.d.ts.map +1 -0
  148. package/lib/updaters/Updater.js +2 -0
  149. package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
  150. package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
  151. package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
  152. package/lib/utils/RemoteTrackResolver.d.ts +7 -0
  153. package/lib/utils/RemoteTrackResolver.d.ts.map +1 -0
  154. package/lib/utils/RemoteTrackResolver.js +2 -0
  155. package/package.json +4 -4
  156. package/src/ObservedCall.ts +276 -164
  157. package/src/ObservedCallEventMonitor.ts +392 -0
  158. package/src/ObservedCallSummary.ts +22 -0
  159. package/src/ObservedCertificate.ts +43 -0
  160. package/src/ObservedClient.ts +630 -1006
  161. package/src/ObservedClientEventMonitor.ts +301 -0
  162. package/src/ObservedClientSummary.ts +24 -0
  163. package/src/ObservedCodec.ts +49 -0
  164. package/src/ObservedDataChannel.ts +71 -181
  165. package/src/ObservedIceCandidate.ts +64 -0
  166. package/src/ObservedIceCandidatePair.ts +134 -0
  167. package/src/ObservedIceTransport.ts +99 -0
  168. package/src/ObservedInboundRtp.ts +205 -0
  169. package/src/ObservedInboundTrack.ts +75 -0
  170. package/src/ObservedMediaPlayout.ts +49 -0
  171. package/src/ObservedMediaSource.ts +60 -0
  172. package/src/ObservedOutboundRtp.ts +156 -0
  173. package/src/ObservedOutboundTrack.ts +74 -0
  174. package/src/ObservedPeerConnection.ts +917 -402
  175. package/src/ObservedPeerConnectionTransport.ts +38 -0
  176. package/src/ObservedRemoteInboundRtp.ts +64 -0
  177. package/src/ObservedRemoteOutboundRtp.ts +65 -0
  178. package/src/ObservedTURN.ts +86 -0
  179. package/src/ObservedTurnServer.ts +72 -0
  180. package/src/Observer.ts +187 -296
  181. package/src/ObserverEventMonitor.ts +551 -0
  182. package/src/ObserverSummary.ts +15 -0
  183. package/src/common/Middleware.ts +70 -42
  184. package/src/common/logger.ts +60 -69
  185. package/src/common/types.ts +0 -42
  186. package/src/common/utils.ts +24 -2
  187. package/src/detectors/Detector.ts +6 -0
  188. package/src/detectors/Detectors.ts +38 -0
  189. package/src/index.ts +26 -88
  190. package/src/monitors/TurnUsageMonitor.ts +164 -164
  191. package/src/schema/ClientEventTypes.ts +280 -0
  192. package/src/schema/ClientMetaTypes.ts +41 -0
  193. package/src/schema/ClientSample.ts +1682 -0
  194. package/src/scores/CalculatedScore.ts +6 -0
  195. package/src/scores/DefaultCallScoreCalculator.ts +23 -0
  196. package/src/scores/ScoreCalculator.ts +3 -0
  197. package/src/updaters/CallUpdater.ts +5 -0
  198. package/src/updaters/ObserverUpdater.ts +5 -0
  199. package/src/updaters/OnAllCallObserverUpdater.ts +59 -0
  200. package/src/updaters/OnAllClientCallUpdater.ts +61 -0
  201. package/src/updaters/OnAnyCallObserverUpdater.ts +41 -0
  202. package/src/updaters/OnAnyClientCallUpdater.ts +39 -0
  203. package/src/updaters/OnIntervalUpdater.ts +19 -0
  204. package/src/updaters/Updater.ts +5 -0
  205. package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
  206. package/src/utils/RemoteTrackResolver.ts +12 -0
  207. package/tsconfig.json +3 -3
  208. package/lib/ObservedICE.d.ts +0 -64
  209. package/lib/ObservedICE.d.ts.map +0 -1
  210. package/lib/ObservedICE.js +0 -141
  211. package/lib/ObservedInboundAudioTrack.d.ts +0 -96
  212. package/lib/ObservedInboundAudioTrack.d.ts.map +0 -1
  213. package/lib/ObservedInboundAudioTrack.js +0 -217
  214. package/lib/ObservedInboundVideoTrack.d.ts +0 -101
  215. package/lib/ObservedInboundVideoTrack.d.ts.map +0 -1
  216. package/lib/ObservedInboundVideoTrack.js +0 -232
  217. package/lib/ObservedOutboundAudioTrack.d.ts +0 -87
  218. package/lib/ObservedOutboundAudioTrack.d.ts.map +0 -1
  219. package/lib/ObservedOutboundAudioTrack.js +0 -186
  220. package/lib/ObservedOutboundVideoTrack.d.ts +0 -91
  221. package/lib/ObservedOutboundVideoTrack.d.ts.map +0 -1
  222. package/lib/ObservedOutboundVideoTrack.js +0 -193
  223. package/lib/ObservedSfu.d.ts +0 -59
  224. package/lib/ObservedSfu.d.ts.map +0 -1
  225. package/lib/ObservedSfu.js +0 -157
  226. package/lib/ObservedSfuInboundRtpPad.d.ts +0 -42
  227. package/lib/ObservedSfuInboundRtpPad.d.ts.map +0 -1
  228. package/lib/ObservedSfuInboundRtpPad.js +0 -71
  229. package/lib/ObservedSfuOutboundRtpPad.d.ts +0 -42
  230. package/lib/ObservedSfuOutboundRtpPad.d.ts.map +0 -1
  231. package/lib/ObservedSfuOutboundRtpPad.js +0 -72
  232. package/lib/ObservedSfuSctpChannel.d.ts +0 -42
  233. package/lib/ObservedSfuSctpChannel.d.ts.map +0 -1
  234. package/lib/ObservedSfuSctpChannel.js +0 -57
  235. package/lib/ObservedSfuTransport.d.ts +0 -58
  236. package/lib/ObservedSfuTransport.d.ts.map +0 -1
  237. package/lib/ObservedSfuTransport.js +0 -120
  238. package/lib/RemoteTrackAssigner.d.ts +0 -14
  239. package/lib/RemoteTrackAssigner.d.ts.map +0 -1
  240. package/lib/RemoteTrackAssigner.js +0 -52
  241. package/lib/ReportsCollector.d.ts +0 -109
  242. package/lib/ReportsCollector.d.ts.map +0 -1
  243. package/lib/ReportsCollector.js +0 -207
  244. package/lib/common/CalculatedScore.d.ts +0 -80
  245. package/lib/common/CalculatedScore.d.ts.map +0 -1
  246. package/lib/common/CalculatedScore.js +0 -162
  247. package/lib/common/CallEventType.d.ts +0 -63
  248. package/lib/common/CallEventType.d.ts.map +0 -1
  249. package/lib/common/CallEventType.js +0 -39
  250. package/lib/common/CallMetaReports.d.ts +0 -42
  251. package/lib/common/CallMetaReports.d.ts.map +0 -1
  252. package/lib/common/CallMetaReports.js +0 -36
  253. package/lib/common/QualityScoreUtils.d.ts +0 -1
  254. package/lib/common/QualityScoreUtils.d.ts.map +0 -1
  255. package/lib/common/QualityScoreUtils.js +0 -1
  256. package/lib/common/TypedEventEmitter.d.ts +0 -22
  257. package/lib/common/TypedEventEmitter.d.ts.map +0 -1
  258. package/lib/common/TypedEventEmitter.js +0 -11
  259. package/lib/common/callEventReports.d.ts +0 -10
  260. package/lib/common/callEventReports.d.ts.map +0 -1
  261. package/lib/common/callEventReports.js +0 -112
  262. package/lib/monitors/CallSummary.d.ts +0 -37
  263. package/lib/monitors/CallSummary.d.ts.map +0 -1
  264. package/lib/monitors/CallSummaryMonitor.d.ts +0 -32
  265. package/lib/monitors/CallSummaryMonitor.d.ts.map +0 -1
  266. package/lib/monitors/CallSummaryMonitor.js +0 -152
  267. package/lib/monitors/ClientIssueMonitor.d.ts +0 -32
  268. package/lib/monitors/ClientIssueMonitor.d.ts.map +0 -1
  269. package/lib/monitors/ClientIssueMonitor.js +0 -49
  270. package/lib/monitors/SfuServerMonitor.d.ts +0 -79
  271. package/lib/monitors/SfuServerMonitor.d.ts.map +0 -1
  272. package/lib/monitors/SfuServerMonitor.js +0 -198
  273. package/src/ObservedICE.ts +0 -237
  274. package/src/ObservedInboundAudioTrack.ts +0 -344
  275. package/src/ObservedInboundVideoTrack.ts +0 -361
  276. package/src/ObservedOutboundAudioTrack.ts +0 -307
  277. package/src/ObservedOutboundVideoTrack.ts +0 -319
  278. package/src/ObservedSfu.ts +0 -231
  279. package/src/ObservedSfuInboundRtpPad.ts +0 -106
  280. package/src/ObservedSfuOutboundRtpPad.ts +0 -107
  281. package/src/ObservedSfuSctpChannel.ts +0 -103
  282. package/src/ObservedSfuTransport.ts +0 -185
  283. package/src/RemoteTrackAssigner.ts +0 -68
  284. package/src/ReportsCollector.ts +0 -336
  285. package/src/common/CalculatedScore.ts +0 -188
  286. package/src/common/CallEventType.ts +0 -69
  287. package/src/common/CallMetaReports.ts +0 -82
  288. package/src/common/QualityScoreUtils.ts +0 -0
  289. package/src/common/TypedEventEmitter.ts +0 -32
  290. package/src/common/callEventReports.ts +0 -178
  291. package/src/monitors/CallSummary.ts +0 -38
  292. package/src/monitors/CallSummaryMonitor.ts +0 -192
  293. package/src/monitors/ClientIssueMonitor.ts +0 -88
  294. package/src/monitors/SfuServerMonitor.ts +0 -285
  295. /package/lib/{monitors/CallSummary.js → ObservedCallSummary.js} +0 -0
@@ -1,123 +1,97 @@
1
- import { Browser, ClientSample, Engine, IceLocalCandidate, IceRemoteCandidate, MediaCodecStats, MediaDevice, OperationSystem, Platform } from '@observertc/sample-schemas-js';
2
- import { ObservedCall } from './ObservedCall';
3
1
  import { EventEmitter } from 'events';
4
2
  import { ObservedPeerConnection } from './ObservedPeerConnection';
5
3
  import { createLogger } from './common/logger';
6
- import { CallMetaType, createCallMetaReport } from './common/CallMetaReports';
7
4
  // eslint-disable-next-line camelcase
8
- import { PartialBy, isValidUuid } from './common/utils';
9
- import { CallEventType } from './common/CallEventType';
10
- import { ObservedSfu } from './ObservedSfu';
11
- import { ClientIssue } from './monitors/CallSummary';
12
- import { CallEventReport } from '@observertc/report-schemas-js';
13
- import { CalculatedScore } from './common/CalculatedScore';
5
+ import { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';
6
+ import * as MetaData from './schema/ClientMetaTypes';
7
+ import { ClientEventTypes } from './schema/ClientEventTypes';
8
+ import { ObservedCall } from './ObservedCall';
9
+ import { ClientMetaTypes } from './schema/ClientMetaTypes';
10
+ import { parseJsonAs } from './common/utils';
11
+ import { CalculatedScore } from './scores/CalculatedScore';
12
+ import { Detectors } from './detectors/Detectors';
14
13
 
15
14
  const logger = createLogger('ObservedClient');
16
15
 
17
- export type ObservedClientModel= {
16
+ export type ObservedClientSettings<AppData extends Record<string, unknown> = Record<string, unknown>> = {
18
17
  clientId: string;
19
- mediaUnitId: string;
20
- userId?: string,
21
- marker?: string,
22
- operationSystem?: OperationSystem,
23
- engine?: Engine,
24
- platform?: Platform,
25
- browser?: Browser,
26
- coordinates?: {
27
- latitude: number;
28
- longitude: number;
29
- },
18
+ appData?: AppData;
30
19
  };
31
20
 
32
21
  export type ObservedClientEvents = {
33
- update: [{
34
- sample: ClientSample,
35
- elapsedTimeInMs: number,
36
- }],
37
- close: [],
38
- joined: [],
39
- left: [],
40
- newpeerconnection: [ObservedPeerConnection],
41
- iceconnectionstatechange: [{
42
- peerConnection: ObservedPeerConnection,
43
- state: string,
44
- }],
45
- icegatheringstatechange: [{
46
- peerConnection: ObservedPeerConnection,
47
- state: string,
48
- }],
49
- connectionstatechange: [{
50
- peerConnection: ObservedPeerConnection,
51
- state: string,
52
- }],
53
- selectedcandidatepair: [{
54
- peerConnection: ObservedPeerConnection,
55
- localCandidate: IceLocalCandidate,
56
- remoteCandidate: IceRemoteCandidate,
57
- }],
58
- issue: [ClientIssue],
59
- usingturn: [boolean],
60
- usermediaerror: [string],
61
- rejoined: [{
62
- lastJoined: number,
63
- }],
64
- score: [CalculatedScore],
22
+ update: [
23
+ {
24
+ sample: ClientSample;
25
+ elapsedTimeInMs: number;
26
+ }
27
+ ];
28
+ close: [];
29
+ joined: [];
30
+ issue: [ClientIssue];
31
+ metaData: [ClientMetaData];
32
+ rejoined: [timestamp: number];
33
+ left: [];
34
+ usingturn: [boolean];
35
+ usermediaerror: [string];
36
+ extensionStats: [ExtensionStat];
37
+ clientEvent: [ClientEvent];
38
+
39
+ newpeerconnection: [ObservedPeerConnection];
65
40
  };
66
41
 
67
- export declare interface ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> {
42
+ export declare interface ObservedClient {
68
43
  on<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
69
44
  off<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
70
45
  once<U extends keyof ObservedClientEvents>(event: U, listener: (...args: ObservedClientEvents[U]) => void): this;
71
46
  emit<U extends keyof ObservedClientEvents>(event: U, ...args: ObservedClientEvents[U]): boolean;
72
- readonly appData: AppData;
73
47
  }
74
48
 
75
- type PendingPeerConnectionTimestamp = {
76
- type: 'opened' | 'closed'
77
- peerConnectionId: string;
78
- timestamp: number;
79
- }
49
+ export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
50
+ public readonly detectors: Detectors;
80
51
 
81
- type PendingMediaTrackTimestamp = {
82
- type: 'added' | 'removed'
83
- peerConnectionId: string;
84
- mediaTrackId: string;
85
- timestamp: number;
86
- }
52
+ public readonly clientId: string;
53
+ public readonly observedPeerConnections = new Map<string, ObservedPeerConnection>();
54
+ public readonly calculatedScore: CalculatedScore = {
55
+ weight: 1,
56
+ value: undefined,
57
+ };
58
+
59
+ public appData: AppData;
60
+ public attachments?: Record<string, unknown>;
87
61
 
88
- export class ObservedClient<AppData extends Record<string, unknown> = Record<string, unknown>> extends EventEmitter {
89
-
90
- public readonly created = Date.now();
91
62
  public updated = Date.now();
92
- public sfuId?: string;
93
-
94
- private readonly _peerConnections = new Map<string, ObservedPeerConnection>();
95
-
96
- private _closed = false;
97
-
98
- private _acceptedSamples = 0;
99
- private _timeZoneOffsetInHours?: number;
63
+ public acceptedSamples = 0;
64
+ public closed = false;
100
65
 
66
+ public joinedAt?: number;
67
+ public leftAt?: number;
68
+ public closedAt?: number;
69
+ public lastSampleTimestamp?: number;
101
70
  // the timestamp of the CLIENT_JOINED event
102
- private _joined?: number;
103
- private _left?: number;
104
- public lastStatsTimestamp?: number;
71
+ public operationSystem?: MetaData.OperationSystem;
72
+ public engine?: MetaData.Engine;
73
+ public platform?: MetaData.Platform;
74
+ public browser?: MetaData.Browser;
75
+ public mediaConstraints: string[] = [];
105
76
 
106
- public score?: CalculatedScore;
107
77
  public usingTURN = false;
78
+ public usingTCP = false;
108
79
  public availableOutgoingBitrate = 0;
109
80
  public availableIncomingBitrate = 0;
81
+
110
82
  public totalInboundPacketsLost = 0;
111
83
  public totalInboundPacketsReceived = 0;
112
84
  public totalOutboundPacketsSent = 0;
113
85
  public totalDataChannelBytesSent = 0;
114
86
  public totalDataChannelBytesReceived = 0;
115
- public totalSentBytes = 0;
116
- public totalReceivedBytes = 0;
87
+ public totalDataChannelMessagesSent = 0;
88
+ public totalDataChannelMessagesReceived = 0;
117
89
  public totalReceivedAudioBytes = 0;
118
90
  public totalReceivedVideoBytes = 0;
119
91
  public totalSentAudioBytes = 0;
120
92
  public totalSentVideoBytes = 0;
93
+ public totalSentBytes = 0;
94
+ public totalReceivedBytes = 0;
121
95
 
122
96
  public deltaReceivedAudioBytes = 0;
123
97
  public deltaReceivedVideoBytes = 0;
@@ -125,1045 +99,695 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
125
99
  public deltaSentVideoBytes = 0;
126
100
  public deltaDataChannelBytesSent = 0;
127
101
  public deltaDataChannelBytesReceived = 0;
102
+ public deltaDataChannelMessagesSent = 0;
103
+ public deltaDataChannelMessagesReceived = 0;
128
104
  public deltaInboundPacketsLost = 0;
129
105
  public deltaInboundPacketsReceived = 0;
130
106
  public deltaOutboundPacketsSent = 0;
131
-
132
- public avgRttInMs?: number;
133
- public outboundAudioBitrate?: number;
134
- public outboundVideoBitrate?: number;
135
- public inboundAudioBitrate?: number;
136
- public inboundVideoBitrate?: number;
137
- public mediaConstraints: string[] = [];
138
-
139
- public readonly mediaDevices: MediaDevice[] = [];
140
- public readonly mediaCodecs: MediaCodecStats[] = [];
141
- public readonly userMediaErrors: string[] = [];
107
+ public deltaTransportSentBytes = 0;
108
+ public deltaTransportReceivedBytes = 0;
109
+ public deltaRttLt50Measurements = 0;
110
+ public deltaRttLt150Measurements = 0;
111
+ public deltaRttLt300Measurements = 0;
112
+ public deltaRttGtOrEq300Measurements = 0;
113
+
114
+ public currentMaxRttInMs?: number;
115
+ public currentMinRttInMs?: number;
116
+ public currentAvgRttInMs?: number;
117
+
118
+ public sendingAudioBitrate = 0;
119
+ public sendingVideoBitrate = 0;
120
+ public receivingAudioBitrate = 0;
121
+ public receivingVideoBitrate = 0;
122
+
123
+ public numberOfInboundRtpStreams = 0;
124
+ public numberOfInbundTracks = 0;
125
+ public numberOfOutboundRtpStreams = 0;
126
+ public numberOfOutboundTracks = 0;
127
+ public numberOfDataChannels = 0;
128
+
129
+ public totalRttLt50Measurements = 0;
130
+ public totalRttLt150Measurements = 0;
131
+ public totalRttLt300Measurements = 0;
132
+ public totalRttGtOrEq300Measurements = 0;
133
+ public deltaNumberOfIssues = 0;
134
+
135
+ public totalScoreSum = 0;
136
+ public numberOfScoreMeasurements = 0;
137
+ public totalNumberOfIssues = 0;
138
+
139
+ public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
142
140
  public issues: ClientIssue[] = [];
143
141
 
144
- public ωpendingPeerConnectionTimestamps: PendingPeerConnectionTimestamp[] = [];
145
- public ωpendingMediaTrackTimestamps: PendingMediaTrackTimestamp[] = [];
146
-
147
- public constructor(
148
- private readonly _model: ObservedClientModel,
149
- public readonly call: ObservedCall,
150
- public readonly appData: AppData
151
- ) {
142
+ private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
143
+
144
+ public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
152
145
  super();
153
146
  this.setMaxListeners(Infinity);
154
- }
155
-
156
- public getSfu<T extends Record<string, unknown> = Record<string, unknown>>(): ObservedSfu<T> | undefined {
157
- const sfu = this.call.observer.observedSfus.get(this.sfuId ?? '');
158
-
159
- if (!sfu) return;
160
-
161
- return sfu as ObservedSfu<T>;
162
- }
163
-
164
- public get joined() {
165
- return this._joined;
166
- }
167
-
168
- public set joined(value: number | undefined) {
169
- this._joined = value;
170
-
171
- if (this._joined) {
172
- this.emit('joined');
173
- }
174
- }
175
-
176
- public get left() {
177
- return this._left;
178
- }
179
147
 
180
- public set left(value: number | undefined) {
181
- this._left = value;
148
+ this.clientId = settings.clientId;
149
+ this.appData = settings.appData ?? {} as AppData;
182
150
 
183
- if (this._left) {
184
- this.emit('left');
185
- }
186
- }
187
-
188
- public get sfu(): ObservedSfu | undefined {
189
- if (!this.sfuId) return;
190
-
191
- return this.call.observer.observedSfus.get(this.sfuId);
192
- }
193
-
194
- public get coordinates() {
195
- return this._model.coordinates;
196
- }
197
-
198
- public set coordinates(value: { latitude: number; longitude: number } | undefined) {
199
- this._model.coordinates = value;
200
- }
201
-
202
- public get clientId(): string {
203
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
204
- return this._model.clientId!;
205
- }
206
-
207
- public get roomId() {
208
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
209
- return this.call.roomId!;
210
- }
211
-
212
- public get serviceId() {
213
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
214
- return this.call.serviceId!;
215
- }
216
-
217
- public get callId() {
218
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
219
- return this.call.callId!;
220
- }
221
-
222
- public get mediaUnitId() {
223
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
224
- return this._model.mediaUnitId!;
225
- }
226
-
227
- public get reports() {
228
- return this.call.reports;
229
- }
230
-
231
- public get userId() {
232
- return this._model.userId;
233
- }
234
-
235
- public set userId(userId: string | undefined) {
236
- this._model.userId = userId;
237
- }
238
-
239
- public get timeZoneOffsetInHours() {
240
- return this._timeZoneOffsetInHours;
151
+ this.detectors = new Detectors();
241
152
  }
242
-
243
- public get marker() {
244
- return this._model.marker;
153
+
154
+ public get numberOfPeerConnections() {
155
+ return this.observedPeerConnections.size;
245
156
  }
246
157
 
247
- public get browser() {
248
- return this._model.browser;
158
+ public get score() {
159
+ return this.calculatedScore.value;
249
160
  }
250
161
 
251
- public get engine() {
252
- return this._model.engine;
253
- }
162
+ public close() {
163
+ if (this.closed) return;
164
+ this.closed = true;
254
165
 
255
- public get operationSystem() {
256
- return this._model.operationSystem;
257
- }
166
+ this._injections.clientEvents?.forEach((clientEvent) => this._processClientEvent(clientEvent));
167
+ this._injections.clientIssues?.forEach((clientIssue) => this.addIssue(clientIssue));
168
+ this._injections.extensionStats?.forEach((extensionStat) => this.addExtensionStats(extensionStat));
169
+ this._injections.clientMetaItems?.forEach((clientMetaItem) => this.addMetadata(clientMetaItem));
258
170
 
259
- public get platform() {
260
- return this._model.platform;
261
- }
171
+ Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
172
+ if (!this.leftAt) {
173
+ this.leftAt = this.lastSampleTimestamp;
262
174
 
263
- public get acceptedSamples() {
264
- return this._acceptedSamples;
265
- }
175
+ if (this.leftAt) {
176
+ this.emit('left');
177
+ }
178
+ }
179
+ this.closedAt = Date.now();
266
180
 
267
- public get closed() {
268
- return this._closed;
181
+ this.emit('close');
269
182
  }
270
183
 
271
- public get peerConnections(): ReadonlyMap<string, ObservedPeerConnection> {
272
- return this._peerConnections;
273
- }
274
-
275
- public close() {
276
- if (this._closed) return;
277
- this._closed = true;
184
+ public accept(sample: ClientSample): void {
185
+ if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
278
186
 
279
- Array.from(this._peerConnections.values()).forEach((peerConnection) => peerConnection.close());
187
+ const now = Date.now();
188
+ const elapsedInMs = now - this.updated;
189
+ const elapsedInSeconds = elapsedInMs / 1000;
190
+ let sumOfRtts = 0;
191
+ let numberOfRttMeasurements = 0;
192
+
193
+ ++this.acceptedSamples;
194
+
195
+ this.availableIncomingBitrate = 0;
196
+ this.availableOutgoingBitrate = 0;
197
+ this.deltaDataChannelBytesReceived = 0;
198
+ this.deltaDataChannelBytesSent = 0;
199
+ this.deltaDataChannelMessagesReceived = 0;
200
+ this.deltaDataChannelMessagesSent = 0;
201
+ this.deltaInboundPacketsLost = 0;
202
+ this.deltaInboundPacketsReceived = 0;
203
+ this.deltaOutboundPacketsSent = 0;
204
+ this.deltaReceivedAudioBytes = 0;
205
+ this.deltaReceivedVideoBytes = 0;
206
+ this.deltaSentAudioBytes = 0;
207
+ this.deltaSentVideoBytes = 0;
208
+ this.deltaTransportReceivedBytes = 0;
209
+ this.deltaTransportSentBytes = 0;
210
+ this.deltaRttLt50Measurements = 0;
211
+ this.deltaRttLt150Measurements = 0;
212
+ this.deltaRttLt300Measurements = 0;
213
+ this.deltaRttGtOrEq300Measurements = 0;
214
+ this.deltaNumberOfIssues = 0;
215
+
216
+ this.numberOfDataChannels = 0;
217
+ this.numberOfInboundRtpStreams = 0;
218
+ this.numberOfInbundTracks = 0;
219
+ this.numberOfOutboundRtpStreams = 0;
220
+ this.numberOfOutboundTracks = 0;
221
+ this.usingTURN = false;
222
+ this.usingTCP = false;
223
+ this.currentMinRttInMs = undefined;
224
+ this.currentMaxRttInMs = undefined;
280
225
 
281
- this.emit('close');
282
- }
226
+ this._mergeInjections(sample);
283
227
 
284
- public addEventReport(params: PartialBy<Omit<CallEventReport, 'serviceId' | 'roomId' | 'callId' | 'clientId' | 'userId' | 'marker' | 'attachments'>, 'timestamp'> & { attachments?: Record<string, unknown> }) {
285
- const {
286
- attachments,
287
- ...fields
288
- } = params;
289
-
290
- this.reports.addCallEventReport({
291
- ...fields,
292
- serviceId: this.serviceId,
293
- mediaUnitId: this.mediaUnitId,
294
- roomId: this.roomId,
295
- callId: this.callId,
296
- clientId: this.clientId,
297
- userId: this.userId,
298
- timestamp: params.timestamp ?? Date.now(),
299
- marker: this.marker,
300
- attachments: attachments ? JSON.stringify(attachments) : undefined,
301
- });
302
- }
228
+ const clientEventsPostBuffer: ClientEvent[] = [];
303
229
 
304
- public addExtensionStatsReport(extensionType: string, payload?: Record<string, unknown>) {
305
- this.reports.addClientExtensionReport({
306
- serviceId: this.serviceId,
307
- mediaUnitId: this.mediaUnitId,
308
- roomId: this.roomId,
309
- callId: this.callId,
310
- clientId: this.clientId,
311
- userId: this.userId,
312
- timestamp: Date.now(),
313
- extensionType,
314
- payload: JSON.stringify(payload),
315
- marker: this.marker,
316
- });
317
- }
230
+ for (const clientEvent of sample.clientEvents ?? []) {
231
+ this._processClientEvent(clientEvent, clientEventsPostBuffer);
318
232
 
319
- public addIssue(issue: ClientIssue) {
320
- try {
321
-
322
- this.reports.addCallEventReport({
323
- serviceId: this.serviceId,
324
- mediaUnitId: this.mediaUnitId,
325
- roomId: this.roomId,
326
- callId: this.callId,
327
- clientId: this.clientId,
328
- userId: this.userId,
329
-
330
- name: CallEventType.CLIENT_ISSUE,
331
- value: issue.severity,
332
- peerConnectionId: issue.peerConnectionId,
333
- mediaTrackId: issue.trackId,
334
- message: issue.description,
335
- timestamp: issue.timestamp ?? Date.now(),
336
- attachments: issue.attachments ? JSON.stringify(issue.attachments): undefined,
337
- });
338
- } catch (err) {
339
- logger.warn(`Error adding client issue: ${(err as Error)?.message}`);
233
+ this.call.observer.emit('client-event', this, clientEvent);
340
234
  }
341
235
 
342
- this._addAndEmitIssue(issue);
343
- }
344
-
345
- public accept(sample: ClientSample): void {
346
- if (this._closed) throw new Error(`Client ${this.clientId} is closed`);
347
- if (sample.clientId && sample.clientId !== 'NULL' && sample.clientId !== this.clientId) {
348
- throw new Error(`Sample client id (${sample.clientId}) does not match the client id of the observed client (${this.clientId})`);
236
+ for (const metaData of sample.clientMetaItems ?? []) {
237
+ this.addMetadata(metaData);
349
238
  }
350
- const now = Date.now();
351
239
 
352
- ++this._acceptedSamples;
353
- if (0 < this.issues.length) {
354
- // we reset the issues every time we accept a new sample
355
- this.issues = [];
356
- }
357
- for (const peerConnection of this._peerConnections.values()) {
358
- if (peerConnection.closed) continue;
359
- peerConnection.resetMetrics();
360
- }
240
+ for (const issue of sample.clientIssues ?? []) {
241
+ this.addIssue(issue);
361
242
 
362
- if (this._model.userId) {
363
- if (sample.userId && sample.userId !== 'NULL' && sample.userId !== this._model.userId) {
364
- this._model.userId = sample.userId;
365
- }
366
- } else if (sample.userId && sample.userId !== 'NULL') {
367
- this._model.userId = sample.userId;
368
- }
369
-
370
- if (this._model.marker !== sample.marker) {
371
- this._model.marker = sample.marker;
372
- this._peerConnections.forEach((peerConnection) => (peerConnection.marker = sample.marker));
243
+ ++this.deltaNumberOfIssues;
373
244
  }
374
245
 
375
- if (this._timeZoneOffsetInHours !== sample.timeZoneOffsetInHours) {
376
- this._timeZoneOffsetInHours = sample.timeZoneOffsetInHours;
246
+ for (const extensionStat of sample.extensionStats ?? []) {
247
+ this.addExtensionStats(extensionStat);
377
248
  }
378
249
 
379
- if (sample.os && (
380
- this._model.operationSystem?.name !== sample.os.name ||
381
- this._model.operationSystem?.version !== sample.os.version ||
382
- this._model.operationSystem?.versionName !== sample.os.versionName
383
- )) {
384
- this._model.operationSystem = sample.os;
385
-
386
- const callMetaReport = createCallMetaReport(
387
- this.serviceId,
388
- this.mediaUnitId,
389
- this.roomId,
390
- this.callId,
391
- this.clientId,
392
- {
393
- type: CallMetaType.OPERATION_SYSTEM,
394
- payload: sample.os,
395
- },
396
- this.userId,
397
- undefined,
398
- sample.timestamp
399
- );
400
-
401
- this.reports.addCallMetaReport(callMetaReport);
402
- }
250
+ for (const pcSample of sample.peerConnections ?? []) {
251
+ const observedPeerConnection = this._updatePeerConnection(pcSample);
403
252
 
404
- if (sample.engine && (
405
- this._model.engine?.name !== sample.engine.name ||
406
- this._model.engine?.version !== sample.engine.version
407
- )) {
408
- this._model.engine = sample.engine;
409
-
410
- const callMetaReport = createCallMetaReport(
411
- this.serviceId,
412
- this.mediaUnitId,
413
- this.roomId,
414
- this.callId,
415
- this.clientId,
416
- {
417
- type: CallMetaType.ENGINE,
418
- payload: sample.engine,
419
- },
420
- this.userId,
421
- undefined,
422
- sample.timestamp
423
- );
424
-
425
- this.reports.addCallMetaReport(callMetaReport);
426
- }
253
+ if (!observedPeerConnection) continue;
427
254
 
428
- if (sample.platform && (
429
- this._model.platform?.model !== sample.platform.model ||
430
- this._model.platform?.type !== sample.platform.type ||
431
- this._model.platform?.vendor !== sample.platform.vendor
432
- )) {
433
- this._model.platform = sample.platform;
434
-
435
- const callMetaReport = createCallMetaReport(
436
- this.serviceId,
437
- this.mediaUnitId,
438
- this.roomId,
439
- this.callId,
440
- this.clientId,
441
- {
442
- type: CallMetaType.PLATFORM,
443
- payload: sample.platform,
444
- },
445
- this.userId,
446
- undefined,
447
- sample.timestamp
448
- );
449
-
450
- this.reports.addCallMetaReport(callMetaReport);
451
- }
255
+ this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
256
+ this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
257
+ this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
258
+ this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
259
+ this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
260
+ this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
261
+ this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
262
+ this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
263
+ this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
264
+ this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
265
+ this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
266
+ this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
267
+ this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
268
+
269
+ this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
270
+ this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
452
271
 
453
- if (sample.browser && (
454
- this._model.browser?.name !== sample.browser.name ||
455
- this._model.browser?.version !== sample.browser.version
456
- )) {
457
- this._model.browser = sample.browser;
458
-
459
- const callMetaReport = createCallMetaReport(
460
- this.serviceId,
461
- this.mediaUnitId,
462
- this.roomId,
463
- this.callId,
464
- this.clientId,
465
- {
466
- type: CallMetaType.BROWSER,
467
- payload: sample.browser,
468
- },
469
- this.userId,
470
- undefined,
471
- sample.timestamp
472
- );
473
-
474
- this.reports.addCallMetaReport(callMetaReport);
475
- }
272
+ this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
273
+ this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
274
+ this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
275
+ this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
276
+ this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
476
277
 
477
- for (const mediaConstraint of sample.mediaConstraints ?? []) {
478
- const callMetaReport = createCallMetaReport(
479
- this.serviceId,
480
- this.mediaUnitId,
481
- this.roomId,
482
- this.callId,
483
- this.clientId,
484
- {
485
- type: CallMetaType.MEDIA_CONSTRAINT,
486
- payload: mediaConstraint,
487
- },
488
- this.userId,
489
- undefined,
490
- sample.timestamp
491
- );
492
-
493
- this.reports.addCallMetaReport(callMetaReport);
494
- this.mediaConstraints.push(mediaConstraint);
495
- }
278
+ if (observedPeerConnection.usingTURN) {
279
+ this.usingTURN = true;
280
+ }
281
+ if (observedPeerConnection.usingTCP) {
282
+ this.usingTCP = true;
283
+ }
284
+
285
+ if (observedPeerConnection.currentRttInMs) {
286
+ if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
287
+ this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
288
+ }
289
+ if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
290
+ this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
291
+ }
292
+ if (observedPeerConnection.currentRttInMs < 50) {
293
+ this.deltaRttLt50Measurements += 1;
294
+ } else if (observedPeerConnection.currentRttInMs < 150) {
295
+ this.deltaRttLt150Measurements += 1;
296
+ } else if (observedPeerConnection.currentRttInMs < 300) {
297
+ this.deltaRttLt300Measurements += 1;
298
+ } else if (300 <= observedPeerConnection.currentRttInMs) {
299
+ this.deltaRttGtOrEq300Measurements += 1;
300
+ }
496
301
 
497
- for (const localSDP of sample.localSDPs ?? []) {
498
- const callMetaReport = createCallMetaReport(
499
- this.serviceId,
500
- this.mediaUnitId,
501
- this.roomId,
502
- this.callId,
503
- this.clientId,
504
- {
505
- type: CallMetaType.LOCAL_SDP,
506
- payload: localSDP,
507
- },
508
- this.userId,
509
- undefined,
510
- sample.timestamp
511
- );
512
-
513
- this.reports.addCallMetaReport(callMetaReport);
302
+ sumOfRtts += observedPeerConnection.currentRttInMs;
303
+ ++numberOfRttMeasurements;
304
+ }
514
305
  }
515
306
 
516
- for (const extensionStats of sample.extensionStats ?? []) {
517
- this.reports.addClientExtensionReport({
518
- serviceId: this.serviceId,
519
- mediaUnitId: this.mediaUnitId,
520
- roomId: this.roomId,
521
- callId: this.callId,
522
- clientId: this.clientId,
523
- userId: this.userId,
524
- timestamp: now,
525
- payload: extensionStats.payload,
526
- extensionType: extensionStats.type,
527
- });
307
+ for (const clientEvent of clientEventsPostBuffer) {
308
+ this._processClientEvent(clientEvent);
528
309
  }
529
310
 
530
- for (const { timestamp, ...callEvent } of sample.customCallEvents ?? []) {
531
- switch (callEvent.name) {
532
- case CallEventType.CLIENT_JOINED: {
533
- const lastJoined = this.joined;
311
+ // emit new attachments?
312
+ this.attachments = sample.attachments;
534
313
 
535
- this.joined = timestamp;
314
+ this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
315
+ this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
316
+ this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
317
+ this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
318
+ this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
319
+ this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
320
+ this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
321
+ this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
322
+ this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
323
+ this.totalSentAudioBytes += this.deltaSentAudioBytes;
324
+ this.totalSentVideoBytes += this.deltaSentVideoBytes;
325
+ this.totalReceivedBytes += this.deltaTransportReceivedBytes;
326
+ this.totalSentBytes += this.deltaTransportSentBytes;
327
+ this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
328
+ this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
329
+ this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
330
+ this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
331
+ this.totalNumberOfIssues += this.deltaNumberOfIssues;
332
+
333
+ this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
334
+ this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
335
+ this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
336
+ this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
337
+ this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
338
+
339
+ this.calculatedScore.value = sample.score;
340
+ this.detectors.update();
341
+
342
+ this.lastSampleTimestamp = sample.timestamp;
343
+ // emit update
344
+ this.emit('update', {
345
+ sample,
346
+ elapsedTimeInMs: now - this.updated,
347
+ });
348
+ this.updated = now;
536
349
 
537
- // if it is joined before and it is joined again
538
- if (lastJoined && this.joined && lastJoined !== this.joined) {
539
- this.emit('rejoined', { lastJoined });
540
- }
541
- // in case we have a left event before the joined event
542
- if (this.left && this.joined && this.left < this.joined) {
543
- this.left = undefined;
350
+ // if result changed after update
351
+ if (this.calculatedScore.value) {
352
+ this.totalScoreSum += this.calculatedScore.value;
353
+ ++this.numberOfScoreMeasurements;
354
+ }
355
+ }
356
+
357
+ private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
358
+ // eslint-disable-next-line no-console
359
+ // console.warn('ClientEvent', event);
360
+ switch (event.type) {
361
+ case ClientEventTypes.CLIENT_JOINED: {
362
+ if (event.timestamp) {
363
+ if (!this.joinedAt) {
364
+ this.joinedAt = event.timestamp;
365
+ this.emit('joined');
366
+ } else if (this.joinedAt < event.timestamp) {
367
+ this.emit('rejoined', event.timestamp);
368
+ } else {
369
+ this.joinedAt = event.timestamp;
370
+ logger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
544
371
  }
545
- break;
546
- }
547
- case CallEventType.CLIENT_LEFT: {
548
- this.left = timestamp;
549
- break;
550
372
  }
551
- case CallEventType.PEER_CONNECTION_OPENED: {
552
- callEvent.peerConnectionId && this.ωpendingPeerConnectionTimestamps.push({
553
- type: 'opened',
554
- peerConnectionId: callEvent.peerConnectionId,
555
- timestamp: timestamp ?? sample.timestamp,
556
- });
557
- break;
373
+ logger.debug('Client %s joined at %o', this.clientId, event);
374
+ break;
375
+ }
376
+ case ClientEventTypes.CLIENT_LEFT: {
377
+ if (event.timestamp) {
378
+ if (!this.leftAt) {
379
+ this.leftAt = event.timestamp;
380
+ this.emit('left');
381
+ } else {
382
+ logger.warn(`Client ${this.clientId} leftAt timestamp was already set`);
383
+ }
384
+
558
385
  }
559
- case CallEventType.PEER_CONNECTION_CLOSED: {
560
- callEvent.peerConnectionId && this.ωpendingPeerConnectionTimestamps.push({
561
- type: 'closed',
562
- peerConnectionId: callEvent.peerConnectionId,
563
- timestamp: timestamp ?? sample.timestamp,
564
- });
565
- break;
386
+ logger.debug('Client %s left at %o', this.clientId, event);
387
+ break;
388
+ }
389
+ case ClientEventTypes.PEER_CONNECTION_OPENED: {
390
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
391
+
392
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
393
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
394
+
395
+ if (observedPeerConnection) {
396
+ observedPeerConnection.openedAt = event.timestamp;
397
+ } else if (postBuffer) {
398
+ postBuffer.push(event);
399
+ } else {
400
+ logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o', event);
401
+ }
402
+
566
403
  }
567
- case CallEventType.MEDIA_TRACK_ADDED: {
568
- callEvent.peerConnectionId && callEvent.mediaTrackId && this.ωpendingMediaTrackTimestamps.push({
569
- type: 'added',
570
- peerConnectionId: callEvent.peerConnectionId,
571
- mediaTrackId: callEvent.mediaTrackId,
572
- timestamp: timestamp ?? sample.timestamp,
573
- });
574
- break;
404
+ break;
405
+ }
406
+ case ClientEventTypes.PEER_CONNECTION_CLOSED: {
407
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
408
+
409
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
410
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
411
+
412
+ if (observedPeerConnection) {
413
+ observedPeerConnection.closedAt = event.timestamp;
414
+ } else if (postBuffer) {
415
+ postBuffer.push(event);
416
+ } else {
417
+ logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o', event);
418
+ }
575
419
  }
576
- case CallEventType.MEDIA_TRACK_REMOVED: {
577
- callEvent.peerConnectionId && callEvent.mediaTrackId && this.ωpendingMediaTrackTimestamps.push({
578
- type: 'removed',
579
- peerConnectionId: callEvent.peerConnectionId,
580
- mediaTrackId: callEvent.mediaTrackId,
581
- timestamp: timestamp ?? sample.timestamp,
582
- });
583
- break;
420
+ break;
421
+ }
422
+ case ClientEventTypes.MEDIA_TRACK_ADDED: {
423
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
424
+
425
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
426
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
427
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
428
+
429
+ if (observedTrack) {
430
+ observedTrack.addedAt = event.timestamp;
431
+ } else if (postBuffer) {
432
+ postBuffer.push(event);
433
+ } else {
434
+ logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o', event);
435
+ }
584
436
  }
585
- case CallEventType.CLIENT_ISSUE: {
586
- const severity = callEvent.value ? callEvent.value as ClientIssue['severity'] : 'minor';
587
-
588
- try {
589
- const issue: ClientIssue = {
590
- severity,
591
- timestamp: timestamp ?? Date.now(),
592
- description: callEvent.message,
593
- peerConnectionId: callEvent.peerConnectionId,
594
- trackId: callEvent.mediaTrackId,
595
- attachments: callEvent.attachments ? JSON.parse(callEvent.attachments) : undefined,
596
- };
597
-
598
- this._addAndEmitIssue(issue);
599
- } catch (err) {
600
- logger.warn(`Error parsing client issue: ${(err as Error)?.message}`);
437
+ break;
438
+ }
439
+ case ClientEventTypes.MEDIA_TRACK_REMOVED: {
440
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
441
+
442
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
443
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
444
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
445
+
446
+ if (observedTrack) {
447
+ observedTrack.removedAt = event.timestamp;
448
+ } else if (postBuffer) {
449
+ postBuffer.push(event);
450
+ } else {
451
+ logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o', event);
601
452
  }
602
- break;
603
453
  }
454
+ break;
604
455
  }
605
-
606
- this.reports.addCallEventReport({
607
- serviceId: this.serviceId,
608
- mediaUnitId: this.mediaUnitId,
609
- roomId: this.roomId,
610
- callId: this.callId,
611
- clientId: this.clientId,
612
- userId: this.userId,
613
- timestamp: timestamp ?? now,
614
- ...callEvent,
615
- });
616
-
617
- this.call.emit('callevent', {
618
- mediaUnitId: this.mediaUnitId,
619
- clientId: this.clientId,
620
- userId: this.userId,
621
- timestamp: timestamp ?? now,
622
- ...callEvent,
623
- });
624
-
625
- }
626
-
627
- for (const userMediaError of sample.userMediaErrors ?? []) {
628
- const callMetaReport = createCallMetaReport(
629
- this.serviceId,
630
- this.mediaUnitId,
631
- this.roomId,
632
- this.callId,
633
- this.clientId, {
634
- type: CallMetaType.USER_MEDIA_ERROR,
635
- payload: userMediaError,
636
- },
637
- this.userId,
638
- );
639
-
640
- this.reports.addCallMetaReport(callMetaReport);
641
- this.userMediaErrors.push(userMediaError);
642
- this.emit('usermediaerror', userMediaError);
643
- }
644
-
645
- for (const certificate of sample.certificates ?? []) {
646
- const callMetaReport = createCallMetaReport(
647
- this.serviceId,
648
- this.mediaUnitId,
649
- this.roomId,
650
- this.callId,
651
- this.clientId, {
652
- type: CallMetaType.CERTIFICATE,
653
- payload: certificate,
654
- },
655
- this.userId
656
- );
657
-
658
- this.reports.addCallMetaReport(callMetaReport);
659
- }
660
-
661
- for (const codec of sample.codecs ?? []) {
662
- const callMetaReport = createCallMetaReport(
663
- this.serviceId,
664
- this.mediaUnitId,
665
- this.roomId,
666
- this.callId,
667
- this.clientId, {
668
- type: CallMetaType.CODEC,
669
- payload: codec,
670
- }, this.userId);
671
-
672
- this.reports.addCallMetaReport(callMetaReport);
673
- if (codec.mimeType && !this.mediaCodecs.find((c) => c.mimeType === codec.mimeType)) {
674
- this.mediaCodecs.push(codec);
456
+ case ClientEventTypes.DATA_CHANNEL_OPEN: {
457
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
458
+
459
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
460
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
461
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
462
+
463
+ if (observedDataChannel) {
464
+ observedDataChannel.addedAt = event.timestamp;
465
+ } else if (postBuffer) {
466
+ postBuffer.push(event);
467
+ } else {
468
+ logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
469
+ }
470
+ }
471
+ break;
675
472
  }
676
- }
677
-
678
- for (const iceServer of sample.iceServers ?? []) {
679
- const callMetaReport = createCallMetaReport(
680
- this.serviceId,
681
- this.mediaUnitId,
682
- this.roomId,
683
- this.callId,
684
- this.clientId, {
685
- type: CallMetaType.ICE_SERVER,
686
- payload: iceServer,
687
- }, this.userId);
688
-
689
- this.reports.addCallMetaReport(callMetaReport);
690
- }
691
-
692
- for (const mediaDevice of sample.mediaDevices ?? []) {
693
- const callMetaReport = createCallMetaReport(
694
- this.serviceId,
695
- this.mediaUnitId,
696
- this.roomId,
697
- this.callId,
698
- this.clientId, {
699
- type: CallMetaType.MEDIA_DEVICE,
700
- payload: mediaDevice,
701
- }, this.userId);
702
-
703
- this.reports.addCallMetaReport(callMetaReport);
704
- if (mediaDevice.id && !this.mediaDevices.find((d) => d.id === mediaDevice.id)) {
705
- this.mediaDevices.push(mediaDevice);
473
+ case ClientEventTypes.DATA_CHANNEL_CLOSED: {
474
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
475
+
476
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
477
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
478
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
479
+
480
+ if (observedDataChannel) {
481
+ observedDataChannel.removedAt = event.timestamp;
482
+ } else if (postBuffer) {
483
+ postBuffer.push(event);
484
+ } else {
485
+ logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
486
+ }
487
+ }
488
+ break;
706
489
  }
707
- }
708
-
709
- for (const mediaSource of sample.mediaSources ?? []) {
710
- const callMetaReport = createCallMetaReport(
711
- this.serviceId,
712
- this.mediaUnitId,
713
- this.roomId,
714
- this.callId,
715
- this.clientId, {
716
- type: CallMetaType.MEDIA_SOURCE,
717
- payload: mediaSource,
718
- }, this.userId);
719
-
720
- this.reports.addCallMetaReport(callMetaReport);
721
- }
722
-
723
- for (const transport of sample.pcTransports ?? []) {
724
- try {
725
- const peerConnection = this._peerConnections.get(transport.transportId) ?? this._createPeerConnection(transport.peerConnectionId);
490
+ case ClientEventTypes.MEDIA_TRACK_MUTED: {
491
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
492
+
493
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
494
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
495
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
496
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
497
+
498
+ if (observedPeerConnection) {
499
+ if (observedInboundTrack) {
500
+ observedInboundTrack.muted = true;
501
+ observedPeerConnection?.emit('muted-inbound-track', observedInboundTrack);
502
+ } else if (observedOutboundTrack) {
503
+ observedOutboundTrack.muted = true;
504
+ observedPeerConnection?.emit('muted-outbound-track', observedOutboundTrack);
505
+ }
506
+ } else if (postBuffer) {
507
+ postBuffer.push(event);
508
+ } else {
509
+ logger.warn('Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
510
+ }
511
+ }
726
512
 
727
- !peerConnection.label && transport.label && (peerConnection.label = transport.label);
728
- peerConnection.update(transport, sample.timestamp);
729
- } catch (err) {
730
- logger.error(`Error creating peer connection: ${(err as Error)?.message}`);
513
+ break;
731
514
  }
732
-
733
- }
734
-
735
- for (const track of sample.inboundAudioTracks ?? []) {
736
- if (!track.peerConnectionId || !track.trackId) {
737
- logger.warn(`InboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
738
-
739
- continue;
515
+ case ClientEventTypes.MEDIA_TRACK_UNMUTED: {
516
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
517
+
518
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
519
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
520
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
521
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
522
+
523
+ if (observedPeerConnection) {
524
+ if (observedInboundTrack) {
525
+ observedInboundTrack.muted = false;
526
+ observedPeerConnection?.emit('unmuted-inbound-track', observedInboundTrack);
527
+ } else if (observedOutboundTrack) {
528
+ observedOutboundTrack.muted = false;
529
+ observedPeerConnection?.emit('unmuted-outbound-track', observedOutboundTrack);
530
+ }
531
+ } else if (postBuffer) {
532
+ postBuffer.push(event);
533
+ } else {
534
+ logger.warn('Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
535
+ }
536
+ }
537
+ break;
740
538
  }
539
+ case ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {
540
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
741
541
 
742
- try {
743
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
542
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {
543
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
744
544
 
745
- if (!peerConnection) continue;
746
-
747
- const inboundAudioTrack = peerConnection.inboundAudioTracks.get(track.trackId) ?? peerConnection.createInboundAudioTrack({
748
- trackId: track.trackId,
749
- sfuStreamId: track.sfuStreamId,
750
- sfuSinkId: track.sfuSinkId,
751
- });
752
-
753
- inboundAudioTrack.update(track, sample.timestamp);
754
-
755
- if (!inboundAudioTrack.remoteOutboundTrack) {
756
- const remoteOutboundTrack = this.call.sfuStreamIdToOutboundAudioTrack.get(inboundAudioTrack.sfuStreamId ?? '');
757
-
758
- if (remoteOutboundTrack) {
759
- inboundAudioTrack.remoteOutboundTrack = remoteOutboundTrack;
760
-
761
- inboundAudioTrack.once('close', () => {
762
- remoteOutboundTrack?.remoteInboundTracks.delete(inboundAudioTrack.trackId ?? '');
545
+ if (observedPeerConnection) {
546
+ observedPeerConnection.iceConnectionState = payload.iceConnectionState;
547
+ observedPeerConnection.emit('iceconnectionstatechange', {
548
+ state: payload.iceConnectionState,
763
549
  });
764
- remoteOutboundTrack.remoteInboundTracks.set(inboundAudioTrack.trackId ?? '', inboundAudioTrack);
550
+ } else if (postBuffer) {
551
+ postBuffer.push(event);
552
+ } else {
553
+ logger.warn('Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
765
554
  }
766
555
  }
767
- } catch (err) {
768
- logger.error(`Error creating inbound audio track: ${(err as Error)?.message}`);
556
+ break;
769
557
  }
770
- }
558
+ case ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {
559
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
771
560
 
772
- for (const track of sample.inboundVideoTracks ?? []) {
773
- if (!track.peerConnectionId || !track.trackId) {
774
- logger.warn(`InboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
561
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {
562
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
775
563
 
776
- continue;
777
- }
778
- if (isValidUuid(track.trackId) === false) {
779
- // mediasoup-probator trackId is not a valid UUID, no need to warn about it
780
- if (track.trackId === 'probator') continue;
781
- logger.warn(`InboundVideoTrack with invalid trackId: ${track.trackId}`);
782
- continue;
564
+ if (observedPeerConnection) {
565
+ observedPeerConnection.iceGatheringState = payload.iceGatheringState;
566
+ observedPeerConnection.emit('icegatheringstatechange', {
567
+ state: payload.iceGatheringState,
568
+ });
569
+ } else if (postBuffer) {
570
+ postBuffer.push(event);
571
+ } else {
572
+ logger.warn('Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
573
+ }
574
+ }
575
+ break;
783
576
  }
577
+ case ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {
578
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
784
579
 
785
- try {
786
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
787
-
788
- if (!peerConnection) continue;
789
-
790
- const inboundVideoTrack = peerConnection.inboundVideoTracks.get(track.trackId) ?? peerConnection.createInboundVideoTrack({
791
- trackId: track.trackId,
792
- sfuStreamId: track.sfuStreamId,
793
- sfuSinkId: track.sfuSinkId,
794
- });
795
-
796
- inboundVideoTrack.update(track, sample.timestamp);
797
-
798
- if (!inboundVideoTrack.remoteOutboundTrack) {
799
- const remoteOutboundTrack = this.call.sfuStreamIdToOutboundVideoTrack.get(inboundVideoTrack.sfuStreamId ?? '');
580
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {
581
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
800
582
 
801
- if (remoteOutboundTrack) {
802
- inboundVideoTrack.remoteOutboundTrack = remoteOutboundTrack;
803
-
804
- inboundVideoTrack.once('close', () => {
805
- remoteOutboundTrack?.remoteInboundTracks.delete(inboundVideoTrack.trackId ?? '');
583
+ if (observedPeerConnection) {
584
+ observedPeerConnection.connectionState = payload.peerConnectionState;
585
+ observedPeerConnection.emit('connectionstatechange', {
586
+ state: payload.peerConnectionState,
806
587
  });
807
- remoteOutboundTrack.remoteInboundTracks.set(inboundVideoTrack.trackId ?? '', inboundVideoTrack);
588
+ } else if (postBuffer) {
589
+ postBuffer.push(event);
590
+ } else {
591
+ logger.warn('Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
808
592
  }
809
593
  }
810
- } catch (err) {
811
- logger.error(`Error creating inbound video track: ${(err as Error)?.message}`);
594
+ break;
812
595
  }
813
596
  }
597
+
598
+ this.emit('clientEvent', event);
599
+ }
600
+
601
+ public injectMetaData(metaData: ClientMetaData) {
602
+ if (this.closed) return;
603
+
604
+ if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
814
605
 
815
- for (const track of sample.outboundAudioTracks ?? []) {
816
- if (!track.peerConnectionId || !track.trackId) {
817
- logger.warn(`OutboundAudioTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
606
+ this._injections.clientMetaItems.push(metaData);
607
+ }
818
608
 
819
- continue;
820
- }
609
+ public injectEvent(event: ClientEvent) {
610
+ if (this.closed) return;
821
611
 
822
- try {
823
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
612
+ if (!this._injections.clientEvents) this._injections.clientEvents = [];
824
613
 
825
- if (!peerConnection) continue;
826
-
827
- const outboundAudioTrack = peerConnection.outboundAudioTracks.get(track.trackId) ?? peerConnection.createOutboundAudioTrack({
828
- trackId: track.trackId,
829
- sfuStreamId: track.sfuStreamId,
830
- });
614
+ this._injections.clientEvents.push(event);
615
+ }
831
616
 
832
- outboundAudioTrack.update(track, sample.timestamp);
617
+ public injectIssue(issue: ClientIssue) {
618
+ if (this.closed) return;
833
619
 
834
- if (outboundAudioTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundAudioTrack.has(outboundAudioTrack.sfuStreamId)) {
835
- this.call.sfuStreamIdToOutboundAudioTrack.set(outboundAudioTrack.sfuStreamId, outboundAudioTrack);
836
- }
620
+ if (!this._injections.clientIssues) this._injections.clientIssues = [];
837
621
 
838
- } catch (err) {
839
- logger.error(`Error creating outbound audio track: ${(err as Error)?.message}`);
840
- }
841
-
842
- }
622
+ this._injections.clientIssues.push(issue);
623
+ }
843
624
 
844
- for (const track of sample.outboundVideoTracks ?? []) {
845
- if (!track.peerConnectionId || !track.trackId) {
846
- logger.warn(`OutboundVideoTrack without peerConnectionId or trackId: ${JSON.stringify(track)}`);
625
+ public injectExtensionStat(stat: ExtensionStat) {
626
+ if (this.closed) return;
847
627
 
848
- continue;
849
- }
628
+ if (!this._injections.extensionStats) this._injections.extensionStats = [];
850
629
 
851
- try {
852
- const peerConnection = this._peerConnections.get(track.peerConnectionId) ?? this._createPeerConnection(track.peerConnectionId);
630
+ this._injections.extensionStats.push(stat);
631
+ }
853
632
 
854
- if (!peerConnection) continue;
855
-
856
- const outboundVideoTrack = peerConnection.outboundVideoTracks.get(track.trackId) ?? peerConnection.createOutboundVideoTrack({
857
- trackId: track.trackId,
858
- sfuStreamId: track.sfuStreamId,
859
- });
860
-
861
- outboundVideoTrack.update(track, sample.timestamp);
633
+ public injectAttachment(key: string, value: unknown) {
634
+ if (this.closed) return;
862
635
 
863
- if (outboundVideoTrack.sfuStreamId && !this.call.sfuStreamIdToOutboundVideoTrack.has(outboundVideoTrack.sfuStreamId)) {
864
- this.call.sfuStreamIdToOutboundVideoTrack.set(outboundVideoTrack.sfuStreamId, outboundVideoTrack);
865
- }
636
+ if (!this._injections.attachments) this._injections.attachments = {};
866
637
 
867
- } catch (err) {
868
- logger.error(`Error creating outbound video track: ${(err as Error)?.message}`);
869
- }
870
- }
638
+ this._injections.attachments[key] = value;
639
+
640
+ }
871
641
 
872
- for (const iceLocalCandidate of sample.iceLocalCandidates ?? []) {
873
- if (!iceLocalCandidate.peerConnectionId) {
874
- logger.warn(`Local ice candidate without peerConnectionId: ${JSON.stringify(iceLocalCandidate)}`);
875
- continue;
642
+ public addMetadata(metadata: ClientMetaData) {
643
+ if (this.closed) return;
644
+
645
+ switch (metadata.type) {
646
+ case ClientMetaTypes.BROWSER: {
647
+ this.browser = parseJsonAs(metadata.payload);
648
+ break;
876
649
  }
877
- const peerConnection = this._peerConnections.get(iceLocalCandidate.peerConnectionId);
878
-
879
- if (!peerConnection) {
880
- logger.debug(`Peer connection ${iceLocalCandidate.peerConnectionId} not found for ice local candidate ${iceLocalCandidate.id}`);
881
- continue;
650
+ case ClientMetaTypes.ENGINE: {
651
+ this.engine = parseJsonAs(metadata.payload);
652
+ break;
882
653
  }
883
-
884
- peerConnection.ICE.addLocalCandidate(iceLocalCandidate, sample.timestamp);
885
- }
886
-
887
- for (const iceRemoteCandidate of sample.iceRemoteCandidates ?? []) {
888
- if (!iceRemoteCandidate.peerConnectionId) {
889
- logger.warn(`Remote ice candidate without peerConnectionId: ${JSON.stringify(iceRemoteCandidate)}`);
890
- continue;
654
+ case ClientMetaTypes.PLATFORM: {
655
+ this.platform = parseJsonAs(metadata.payload);
656
+ break;
891
657
  }
892
- const peerConnection = this._peerConnections.get(iceRemoteCandidate.peerConnectionId);
893
-
894
- if (!peerConnection) {
895
- logger.debug(`Peer connection ${iceRemoteCandidate.peerConnectionId} not found for ice remote candidate ${iceRemoteCandidate.id}`);
896
- continue;
658
+ case ClientMetaTypes.OPERATION_SYSTEM: {
659
+ this.operationSystem = parseJsonAs(metadata.payload);
660
+ break;
897
661
  }
898
-
899
- peerConnection.ICE.addRemoteCandidate(iceRemoteCandidate, sample.timestamp);
900
662
  }
901
663
 
902
- for (const candidatePair of sample.iceCandidatePairs ?? []) {
903
- const peerConnection = this._peerConnections.get(candidatePair.peerConnectionId);
664
+ this.call.observer.emit('client-metadata', this, metadata);
665
+ }
904
666
 
905
- if (!peerConnection) {
906
- logger.debug(`Peer connection ${candidatePair.peerConnectionId} not found for ice candidate pair ${candidatePair.localCandidateId}, ${candidatePair.remoteCandidateId}`);
667
+ public addIssue(issue: ClientIssue) {
668
+ if (this.closed) return;
907
669
 
908
- continue;
909
- }
670
+ this.emit('issue', issue);
671
+ this.call.observer.emit('client-issue', this, issue);
672
+ }
910
673
 
911
- peerConnection.ICE.update(candidatePair, sample.timestamp);
912
- }
674
+ public addExtensionStats(stats: ExtensionStat) {
675
+ this.call.observer.emit('client-extension-stats', this, stats);
676
+ this.emit('extensionStats', stats);
677
+ }
913
678
 
914
- for (const dataChannel of sample.dataChannels ?? []) {
915
- if (!dataChannel.peerConnectionId || !dataChannel.dataChannelIdentifier) {
916
- logger.warn(`DataChannel without peerConnectionId or dataChannelIdentifier: ${JSON.stringify(dataChannel)}`);
679
+ private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
680
+ let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
917
681
 
918
- continue;
682
+ if (!observedPeerConnection) {
683
+ if (!sample.peerConnectionId) {
684
+ return (logger.warn(
685
+ `ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
686
+ sample
687
+ ), void 0);
919
688
  }
920
689
 
921
- try {
922
- const peerConnection = this._peerConnections.get(dataChannel.peerConnectionId) ?? this._createPeerConnection(dataChannel.peerConnectionId);
690
+ observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
923
691
 
924
- if (!peerConnection) continue;
925
-
926
- const observedDataChannel = peerConnection.dataChannels.get(dataChannel.dataChannelIdentifier) ?? peerConnection.createDataChannel(dataChannel.dataChannelIdentifier);
927
-
928
- observedDataChannel.update(dataChannel, sample.timestamp);
929
- } catch (err) {
930
- logger.error(`Error creating data channel: ${(err as Error)?.message}`);
931
- }
692
+ observedPeerConnection.once('close', () => {
693
+ this.observedPeerConnections.delete(sample.peerConnectionId);
694
+ });
695
+ this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
696
+
697
+ this.emit('newpeerconnection', observedPeerConnection);
932
698
  }
933
699
 
934
- // try to set the timestamps of the peer connections
935
- if (0 < this.ωpendingPeerConnectionTimestamps.length) {
936
- const newPendingTimestamps: PendingPeerConnectionTimestamp[] = [];
700
+ observedPeerConnection.accept(sample);
937
701
 
938
- for (const pendingTimestamp of this.ωpendingPeerConnectionTimestamps) {
939
- const peerConnection = this._peerConnections.get(pendingTimestamp.peerConnectionId);
702
+ return observedPeerConnection;
703
+ }
940
704
 
941
- if (!peerConnection) {
942
- newPendingTimestamps.push(pendingTimestamp);
943
- continue;
944
- }
945
- if (pendingTimestamp.type === 'opened') peerConnection.opened = pendingTimestamp.timestamp;
946
- else if (pendingTimestamp.type === 'closed') peerConnection.closedTimestamp = pendingTimestamp.timestamp;
947
- }
705
+ private _mergeInjections(sample: ClientSample): ClientSample {
706
+ if (this.closed) return sample;
948
707
 
949
- this.ωpendingPeerConnectionTimestamps = newPendingTimestamps;
708
+ if (this._injections.clientEvents) {
709
+ if (!sample.clientEvents) sample.clientEvents = [];
710
+ sample.clientEvents.push(...this._injections.clientEvents);
711
+
712
+ this._injections.clientEvents = undefined;
950
713
  }
951
-
952
- // try to set the timestamps of the media tracks
953
- if (0 < this.ωpendingMediaTrackTimestamps.length) {
954
- const newPendingTimestamps: PendingMediaTrackTimestamp[] = [];
955
-
956
- for (const pendingTimestamp of this.ωpendingMediaTrackTimestamps) {
957
- const peerConnection = this._peerConnections.get(pendingTimestamp.peerConnectionId);
958
- const mediaTrack = peerConnection?.inboundAudioTracks.get(pendingTimestamp.mediaTrackId) ??
959
- peerConnection?.inboundVideoTracks.get(pendingTimestamp.mediaTrackId) ??
960
- peerConnection?.outboundAudioTracks.get(pendingTimestamp.mediaTrackId) ??
961
- peerConnection?.outboundVideoTracks.get(pendingTimestamp.mediaTrackId);
962
-
963
- if (!mediaTrack) {
964
- newPendingTimestamps.push(pendingTimestamp);
965
- continue;
966
- }
967
-
968
- if (pendingTimestamp.type === 'added') mediaTrack.added = pendingTimestamp.timestamp;
969
- else if (pendingTimestamp.type === 'removed') mediaTrack.removed = pendingTimestamp.timestamp;
970
- }
971
714
 
972
- this.ωpendingMediaTrackTimestamps = newPendingTimestamps;
715
+ if (this._injections.clientIssues) {
716
+ if (!sample.clientIssues) sample.clientIssues = [];
717
+ sample.clientIssues.push(...this._injections.clientIssues);
718
+
719
+ this._injections.clientIssues = undefined;
973
720
  }
974
721
 
975
- // close resources that are not visited
976
- for (const peerConnection of this._peerConnections.values()) {
977
- if (!peerConnection.visited) {
978
- peerConnection.close();
979
-
980
- continue;
981
- }
982
-
983
- for (const track of peerConnection.inboundAudioTracks.values()) {
984
- if (!track.visited) {
985
- track.close();
986
-
987
- continue;
988
- }
989
-
990
- track.visited = false;
991
- }
992
- for (const track of peerConnection.inboundVideoTracks.values()) {
993
- if (!track.visited) {
994
- track.close();
995
-
996
- continue;
997
- }
998
-
999
- track.visited = false;
1000
- }
1001
- for (const track of peerConnection.outboundAudioTracks.values()) {
1002
- if (!track.visited) {
1003
- track.close();
1004
-
1005
- continue;
1006
- }
1007
-
1008
- track.visited = false;
1009
- }
1010
- for (const dataChannel of peerConnection.dataChannels.values()) {
1011
- if (!dataChannel.visited) {
1012
- dataChannel.close();
1013
-
1014
- continue;
1015
- }
1016
-
1017
- dataChannel.visited = false;
1018
- }
1019
-
1020
- peerConnection.visited = false;
722
+ if (this._injections.extensionStats) {
723
+ if (!sample.extensionStats) sample.extensionStats = [];
724
+ sample.extensionStats.push(...this._injections.extensionStats);
725
+
726
+ this._injections.extensionStats = undefined;
1021
727
  }
1022
728
 
1023
- // update metrics
1024
- const wasUsingTURN = this.usingTURN;
1025
- const elapsedTimeInMs = now - this.updated;
1026
-
1027
- this.usingTURN = false;
1028
- this.availableIncomingBitrate = 0;
1029
- this.availableOutgoingBitrate = 0;
1030
- this.deltaInboundPacketsLost = 0;
1031
- this.deltaInboundPacketsReceived = 0;
1032
- this.deltaOutboundPacketsSent = 0;
1033
- this.deltaReceivedAudioBytes = 0;
1034
- this.deltaReceivedVideoBytes = 0;
1035
- this.deltaSentAudioBytes = 0;
1036
- this.deltaSentVideoBytes = 0;
1037
- this.deltaDataChannelBytesReceived = 0;
1038
- this.deltaDataChannelBytesSent = 0;
1039
-
1040
- this.outboundAudioBitrate = 0;
1041
- this.outboundVideoBitrate = 0;
1042
- this.inboundAudioBitrate = 0;
1043
- this.inboundVideoBitrate = 0;
1044
- let sumRttInMs = 0;
1045
- let anyPeerConnectionUsingTurn = false;
1046
-
1047
- let minPcScore: number | undefined;
1048
- let maxPcScore: number | undefined;
1049
- let numberOfScoredPeerConnections = 0;
1050
-
1051
- for (const peerConnection of this._peerConnections.values()) {
1052
- if (peerConnection.closed) continue;
1053
- peerConnection.updateMetrics();
1054
- this.deltaInboundPacketsLost += peerConnection.deltaInboundPacketsLost;
1055
- this.deltaInboundPacketsReceived += peerConnection.deltaInboundPacketsReceived;
1056
- this.deltaOutboundPacketsSent += peerConnection.deltaOutboundPacketsSent;
1057
- this.deltaReceivedAudioBytes += peerConnection.deltaReceivedAudioBytes;
1058
- this.deltaReceivedVideoBytes += peerConnection.deltaReceivedVideoBytes;
1059
- this.deltaSentAudioBytes += peerConnection.deltaSentAudioBytes;
1060
- this.deltaSentVideoBytes += peerConnection.deltaSentVideoBytes;
1061
- this.deltaDataChannelBytesReceived += peerConnection.deltaDataChannelBytesReceived;
1062
- this.deltaDataChannelBytesSent += peerConnection.deltaDataChannelBytesSent;
1063
-
1064
- this.availableIncomingBitrate += peerConnection.availableIncomingBitrate ?? 0;
1065
- this.availableOutgoingBitrate += peerConnection.availableOutgoingBitrate ?? 0;
1066
-
1067
- sumRttInMs += peerConnection.avgRttInMs ?? 0;
1068
-
1069
- anyPeerConnectionUsingTurn ||= peerConnection.usingTURN;
1070
-
1071
- if (peerConnection.score) {
1072
- if (minPcScore === undefined || peerConnection.score.score < minPcScore) minPcScore = peerConnection.score.score;
1073
- if (maxPcScore === undefined || peerConnection.score.score > maxPcScore) maxPcScore = peerConnection.score.score;
1074
-
1075
- ++numberOfScoredPeerConnections;
1076
- }
729
+ if (this._injections.attachments) {
730
+ if (!sample.attachments) sample.attachments = {};
731
+ Object.assign(sample.attachments, this._injections.attachments);
732
+
733
+ this._injections.attachments = undefined;
1077
734
  }
1078
735
 
1079
- this.score = {
1080
- score: minPcScore ?? -1,
1081
- remarks: [ {
1082
- severity: 'none',
1083
- text: `Min and max score of all peer connections: ${minPcScore}, ${maxPcScore}, number of PeerConnections with scores: ${numberOfScoredPeerConnections}`,
1084
- } ],
1085
- timestamp: sample.timestamp,
1086
- };
1087
- this.emit('score', this.score);
1088
-
1089
- this.usingTURN = anyPeerConnectionUsingTurn === true;
1090
-
1091
- if (wasUsingTURN !== this.usingTURN) this.emit('usingturn', this.usingTURN);
1092
-
1093
- this.totalSentBytes += this.deltaSentAudioBytes + this.deltaSentVideoBytes;
1094
- this.totalReceivedBytes += this.deltaReceivedAudioBytes + this.deltaReceivedVideoBytes;
1095
- this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
1096
- this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
1097
- this.totalSentAudioBytes += this.deltaSentAudioBytes;
1098
- this.totalSentVideoBytes += this.deltaSentVideoBytes;
1099
- this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
1100
- this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
1101
- this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
1102
- this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
1103
- this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
736
+ if (this._injections.clientMetaItems) {
737
+ if (!sample.clientMetaItems) sample.clientMetaItems = [];
738
+ sample.clientMetaItems.push(...this._injections.clientMetaItems);
739
+
740
+ this._injections.clientMetaItems = undefined;
741
+ }
742
+
743
+ return sample;
744
+ }
745
+
746
+ // public resetSummaryMetrics() {
747
+ // this.totalDataChannelBytesReceived = 0;
748
+ // this.totalDataChannelBytesSent = 0;
749
+ // this.totalDataChannelMessagesReceived = 0;
750
+ // this.totalDataChannelMessagesSent = 0;
751
+ // this.totalInboundPacketsLost = 0;
752
+ // this.totalInboundPacketsReceived = 0;
753
+ // this.totalOutboundPacketsSent = 0;
754
+ // this.totalReceivedAudioBytes = 0;
755
+ // this.totalReceivedVideoBytes = 0;
756
+ // this.totalSentAudioBytes = 0;
757
+ // this.totalSentVideoBytes = 0;
758
+ // this.totalSentBytes = 0;
759
+ // this.totalReceivedBytes = 0;
1104
760
 
1105
- this.outboundAudioBitrate = (this.deltaSentAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
1106
- this.outboundVideoBitrate = (this.deltaSentVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
1107
- this.inboundAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
1108
- this.inboundVideoBitrate = (this.deltaReceivedVideoBytes * 8) / (Math.max(elapsedTimeInMs, 1) / 1000);
1109
-
1110
- this.avgRttInMs = this._peerConnections.size ? sumRttInMs / this._peerConnections.size : undefined;
761
+ // this.totalNumberOfIssues = 0;
1111
762
 
1112
- // to make sure when sample is emitted it can be associated to this client
1113
- sample.clientId = this.clientId;
1114
-
1115
- this.updated = now;
1116
- this.lastStatsTimestamp = sample.timestamp;
1117
- this.emit('update', {
1118
- sample,
1119
- elapsedTimeInMs,
1120
- });
1121
- }
1122
-
1123
- private _addAndEmitIssue(issue: ClientIssue) {
1124
- this.issues.push(issue);
1125
-
1126
- if (issue.peerConnectionId) {
1127
- const peerConnection = this._peerConnections.get(issue.peerConnectionId);
1128
-
1129
- if (peerConnection) {
1130
-
1131
- if (issue.trackId) {
1132
- const track = peerConnection.inboundAudioTracks.get(issue.trackId) ?? peerConnection.inboundVideoTracks.get(issue.trackId);
1133
-
1134
- if (track) track.ωpendingIssuesForScores.push(issue);
1135
- } else {
1136
- peerConnection.ωpendingIssuesForScores.push(issue);
1137
- }
1138
- }
1139
- }
1140
-
1141
- this.emit('issue', issue);
1142
- }
1143
-
1144
- private _createPeerConnection(peerConnectionId: string, label?: string): ObservedPeerConnection {
1145
- const result = new ObservedPeerConnection({
1146
- peerConnectionId,
1147
- label,
1148
- }, this);
1149
-
1150
- const onNewSelectedCandidatePair = ({ localCandidate, remoteCandidate }: { localCandidate: IceLocalCandidate, remoteCandidate: IceRemoteCandidate }) => {
1151
- this.emit('selectedcandidatepair', {
1152
- peerConnection: result,
1153
- localCandidate,
1154
- remoteCandidate,
1155
- });
1156
- };
1157
-
1158
- result.once('close', () => {
1159
- result.ICE.off('new-selected-candidate-pair', onNewSelectedCandidatePair);
1160
- this._peerConnections.delete(peerConnectionId);
1161
- });
1162
- result.ICE.on('new-selected-candidate-pair', onNewSelectedCandidatePair);
1163
- this._peerConnections.set(peerConnectionId, result);
1164
-
1165
- this.emit('newpeerconnection', result);
763
+ // this.totalScoreSum = 0;
764
+ // this.numberOfScoreMeasurements = 0;
765
+ // }
766
+
767
+ // public createSummary(): ObservedClientSummary {
768
+ // return {
769
+ // totalRttLt50Measurements: this.totalRttLt50Measurements,
770
+ // totalRttLt150Measurements: this.totalRttLt150Measurements,
771
+ // totalRttLt300Measurements: this.totalRttLt300Measurements,
772
+ // totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
773
+ // totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
774
+ // totalDataChannelBytesSent: this.totalDataChannelBytesSent,
775
+ // totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
776
+ // totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
777
+ // totalInboundPacketsLost: this.totalInboundPacketsLost,
778
+ // totalInboundPacketsReceived: this.totalInboundPacketsReceived,
779
+ // totalOutboundPacketsSent: this.totalOutboundPacketsSent,
780
+ // totalReceivedAudioBytes: this.totalReceivedAudioBytes,
781
+ // totalReceivedVideoBytes: this.totalReceivedVideoBytes,
782
+ // totalSentAudioBytes: this.totalSentAudioBytes,
783
+ // totalSentVideoBytes: this.totalSentVideoBytes,
784
+ // totalSentBytes: this.totalSentBytes,
785
+ // totalReceivedBytes: this.totalReceivedBytes,
786
+
787
+ // numberOfIssues: this.totalNumberOfIssues,
1166
788
 
1167
- return result;
1168
- }
1169
- }
789
+ // totalScoreSum: this.totalScoreSum,
790
+ // numberOfScoreMeasurements: this.numberOfScoreMeasurements,
791
+ // };
792
+ // }
793
+ }