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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/lib/ObservedCall.d.ts +43 -7
  2. package/lib/ObservedCall.d.ts.map +1 -1
  3. package/lib/ObservedCall.js +142 -14
  4. package/lib/ObservedCallEventMonitor.d.ts +104 -0
  5. package/lib/ObservedCallEventMonitor.d.ts.map +1 -0
  6. package/lib/ObservedCallEventMonitor.js +314 -0
  7. package/lib/ObservedCallSummary.d.ts +18 -0
  8. package/lib/ObservedCallSummary.d.ts.map +1 -0
  9. package/lib/ObservedClient.d.ts +71 -11
  10. package/lib/ObservedClient.d.ts.map +1 -1
  11. package/lib/ObservedClient.js +509 -72
  12. package/lib/ObservedClientEventMonitor.d.ts +89 -0
  13. package/lib/ObservedClientEventMonitor.d.ts.map +1 -0
  14. package/lib/ObservedClientEventMonitor.js +247 -0
  15. package/lib/ObservedClientSummary.d.ts +23 -0
  16. package/lib/ObservedClientSummary.d.ts.map +1 -0
  17. package/lib/ObservedClientSummary.js +2 -0
  18. package/lib/ObservedDataChannel.d.ts +6 -0
  19. package/lib/ObservedDataChannel.d.ts.map +1 -1
  20. package/lib/ObservedDataChannel.js +30 -0
  21. package/lib/ObservedIceCandidatePair.d.ts +6 -1
  22. package/lib/ObservedIceCandidatePair.d.ts.map +1 -1
  23. package/lib/ObservedIceCandidatePair.js +45 -1
  24. package/lib/ObservedIceTransport.d.ts +4 -0
  25. package/lib/ObservedIceTransport.d.ts.map +1 -1
  26. package/lib/ObservedIceTransport.js +28 -0
  27. package/lib/ObservedInboundTrack.d.ts +3 -0
  28. package/lib/ObservedInboundTrack.d.ts.map +1 -1
  29. package/lib/ObservedInboundTrack.js +3 -0
  30. package/lib/ObservedOutboundTrack.d.ts +3 -0
  31. package/lib/ObservedOutboundTrack.d.ts.map +1 -1
  32. package/lib/ObservedOutboundTrack.js +3 -0
  33. package/lib/ObservedPeerConnection.d.ts +36 -2
  34. package/lib/ObservedPeerConnection.d.ts.map +1 -1
  35. package/lib/ObservedPeerConnection.js +184 -29
  36. package/lib/ObservedTURN.d.ts +31 -0
  37. package/lib/ObservedTURN.d.ts.map +1 -0
  38. package/lib/ObservedTURN.js +58 -0
  39. package/lib/ObservedTurnServer.d.ts +25 -0
  40. package/lib/ObservedTurnServer.d.ts.map +1 -0
  41. package/lib/ObservedTurnServer.js +59 -0
  42. package/lib/Observer.d.ts +43 -22
  43. package/lib/Observer.d.ts.map +1 -1
  44. package/lib/Observer.js +126 -40
  45. package/lib/ObserverEventMonitor.d.ts +138 -0
  46. package/lib/ObserverEventMonitor.d.ts.map +1 -0
  47. package/lib/ObserverEventMonitor.js +433 -0
  48. package/lib/ObserverSummary.d.ts +13 -0
  49. package/lib/ObserverSummary.d.ts.map +1 -0
  50. package/lib/ObserverSummary.js +2 -0
  51. package/lib/common/utils.d.ts +2 -1
  52. package/lib/common/utils.d.ts.map +1 -1
  53. package/lib/common/utils.js +11 -3
  54. package/lib/index.d.ts +6 -0
  55. package/lib/index.d.ts.map +1 -1
  56. package/lib/index.js +9 -1
  57. package/lib/schema/ClientEventTypes.d.ts +228 -0
  58. package/lib/schema/ClientEventTypes.d.ts.map +1 -0
  59. package/lib/schema/ClientEventTypes.js +41 -0
  60. package/lib/schema/{metaTypes.d.ts → ClientMetaTypes.d.ts} +2 -2
  61. package/lib/schema/ClientMetaTypes.d.ts.map +1 -0
  62. package/lib/schema/ClientMetaTypes.js +16 -0
  63. package/lib/schema/ClientSample.d.ts +1 -1
  64. package/lib/schema/ClientSample.d.ts.map +1 -1
  65. package/lib/updaters/CallUpdater.d.ts.map +1 -0
  66. package/lib/updaters/CallUpdater.js +2 -0
  67. package/lib/updaters/ObserverUpdater.d.ts +5 -0
  68. package/lib/updaters/ObserverUpdater.d.ts.map +1 -0
  69. package/lib/updaters/ObserverUpdater.js +2 -0
  70. package/lib/updaters/OnAllCallObserverUpdater.d.ts +15 -0
  71. package/lib/updaters/OnAllCallObserverUpdater.d.ts.map +1 -0
  72. package/lib/updaters/OnAllCallObserverUpdater.js +50 -0
  73. package/lib/updaters/OnAllClientCallUpdater.d.ts +15 -0
  74. package/lib/updaters/OnAllClientCallUpdater.d.ts.map +1 -0
  75. package/lib/updaters/OnAllClientCallUpdater.js +53 -0
  76. package/lib/updaters/OnAnyCallObserverUpdater.d.ts +12 -0
  77. package/lib/updaters/OnAnyCallObserverUpdater.d.ts.map +1 -0
  78. package/lib/updaters/OnAnyCallObserverUpdater.js +37 -0
  79. package/lib/updaters/OnAnyClientCallUpdater.d.ts +12 -0
  80. package/lib/updaters/OnAnyClientCallUpdater.d.ts.map +1 -0
  81. package/lib/updaters/OnAnyClientCallUpdater.js +36 -0
  82. package/lib/updaters/OnIntervalUpdater.d.ts +10 -0
  83. package/lib/updaters/OnIntervalUpdater.d.ts.map +1 -0
  84. package/lib/updaters/OnIntervalUpdater.js +17 -0
  85. package/lib/updaters/Updater.d.ts +6 -0
  86. package/lib/updaters/Updater.d.ts.map +1 -0
  87. package/lib/updaters/Updater.js +2 -0
  88. package/lib/utils/MediasoupRemoteTrackResolver.d.ts +25 -0
  89. package/lib/utils/MediasoupRemoteTrackResolver.d.ts.map +1 -0
  90. package/lib/utils/MediasoupRemoteTrackResolver.js +110 -0
  91. package/package.json +1 -1
  92. package/src/ObservedCall.ts +222 -17
  93. package/src/ObservedCallEventMonitor.ts +392 -0
  94. package/src/ObservedCallSummary.ts +22 -0
  95. package/src/ObservedClient.ts +608 -79
  96. package/src/ObservedClientEventMonitor.ts +301 -0
  97. package/src/ObservedClientSummary.ts +24 -0
  98. package/src/ObservedDataChannel.ts +32 -0
  99. package/src/ObservedIceCandidatePair.ts +44 -2
  100. package/src/ObservedIceTransport.ts +29 -0
  101. package/src/ObservedInboundTrack.ts +5 -0
  102. package/src/ObservedOutboundTrack.ts +5 -0
  103. package/src/ObservedPeerConnection.ts +219 -46
  104. package/src/ObservedTURN.ts +86 -0
  105. package/src/ObservedTurnServer.ts +72 -0
  106. package/src/Observer.ts +179 -64
  107. package/src/ObserverEventMonitor.ts +551 -0
  108. package/src/ObserverSummary.ts +15 -0
  109. package/src/common/utils.ts +12 -2
  110. package/src/index.ts +6 -1
  111. package/src/schema/ClientEventTypes.ts +280 -0
  112. package/src/schema/{metaTypes.ts → ClientMetaTypes.ts} +1 -1
  113. package/src/schema/ClientSample.ts +1 -1
  114. package/src/updaters/ObserverUpdater.ts +5 -0
  115. package/src/updaters/OnAllCallObserverUpdater.ts +59 -0
  116. package/src/updaters/OnAllClientCallUpdater.ts +61 -0
  117. package/src/updaters/OnAnyCallObserverUpdater.ts +41 -0
  118. package/src/updaters/OnAnyClientCallUpdater.ts +39 -0
  119. package/src/updaters/OnIntervalUpdater.ts +19 -0
  120. package/src/updaters/Updater.ts +5 -0
  121. package/src/utils/MediasoupRemoteTrackResolver.ts +155 -0
  122. package/tsconfig.json +1 -1
  123. package/lib/schema/eventTypes.d.ts +0 -33
  124. package/lib/schema/eventTypes.d.ts.map +0 -1
  125. package/lib/schema/eventTypes.js +0 -38
  126. package/lib/schema/metaTypes.d.ts.map +0 -1
  127. package/lib/schema/metaTypes.js +0 -16
  128. package/lib/utils/CallUpdater.d.ts.map +0 -1
  129. package/lib/utils/OnAllClientCallUpdater.d.ts +0 -16
  130. package/lib/utils/OnAllClientCallUpdater.d.ts.map +0 -1
  131. package/lib/utils/OnAllClientCallUpdater.js +0 -58
  132. package/lib/utils/onAnyClientCallUpdater.d.ts +0 -14
  133. package/lib/utils/onAnyClientCallUpdater.d.ts.map +0 -1
  134. package/lib/utils/onAnyClientCallUpdater.js +0 -51
  135. package/src/schema/eventTypes.ts +0 -36
  136. package/src/utils/OnAllClientCallUpdater.ts +0 -68
  137. package/src/utils/onAnyClientCallUpdater.ts +0 -59
  138. /package/lib/{utils/CallUpdater.js → ObservedCallSummary.js} +0 -0
  139. /package/lib/{utils → updaters}/CallUpdater.d.ts +0 -0
  140. /package/src/{utils → updaters}/CallUpdater.ts +0 -0
@@ -3,10 +3,10 @@ import { ObservedPeerConnection } from './ObservedPeerConnection';
3
3
  import { createLogger } from './common/logger';
4
4
  // eslint-disable-next-line camelcase
5
5
  import { ClientEvent, ClientMetaData, ClientSample, PeerConnectionSample, ClientIssue, ExtensionStat } from './schema/ClientSample';
6
- import * as MetaData from './schema/metaTypes';
7
- import { ClientEventType } from './schema/eventTypes';
6
+ import * as MetaData from './schema/ClientMetaTypes';
7
+ import { ClientEventTypes } from './schema/ClientEventTypes';
8
8
  import { ObservedCall } from './ObservedCall';
9
- import { ClientMetaType } from './schema/metaTypes';
9
+ import { ClientMetaTypes } from './schema/ClientMetaTypes';
10
10
  import { parseJsonAs } from './common/utils';
11
11
  import { CalculatedScore } from './scores/CalculatedScore';
12
12
  import { Detectors } from './detectors/Detectors';
@@ -27,12 +27,15 @@ export type ObservedClientEvents = {
27
27
  ];
28
28
  close: [];
29
29
  joined: [];
30
+ issue: [ClientIssue];
31
+ metaData: [ClientMetaData];
30
32
  rejoined: [timestamp: number];
31
33
  left: [];
32
34
  usingturn: [boolean];
33
35
  usermediaerror: [string];
36
+ extensionStats: [ExtensionStat];
37
+ clientEvent: [ClientEvent];
34
38
 
35
- // do we need this?
36
39
  newpeerconnection: [ObservedPeerConnection];
37
40
  };
38
41
 
@@ -53,7 +56,7 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
53
56
  value: undefined,
54
57
  };
55
58
 
56
- public appData?: AppData;
59
+ public appData: AppData;
57
60
  public attachments?: Record<string, unknown>;
58
61
 
59
62
  public updated = Date.now();
@@ -62,6 +65,8 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
62
65
 
63
66
  public joinedAt?: number;
64
67
  public leftAt?: number;
68
+ public closedAt?: number;
69
+ public lastSampleTimestamp?: number;
65
70
  // the timestamp of the CLIENT_JOINED event
66
71
  public operationSystem?: MetaData.OperationSystem;
67
72
  public engine?: MetaData.Engine;
@@ -70,47 +75,85 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
70
75
  public mediaConstraints: string[] = [];
71
76
 
72
77
  public usingTURN = false;
78
+ public usingTCP = false;
73
79
  public availableOutgoingBitrate = 0;
74
80
  public availableIncomingBitrate = 0;
75
- // public totalInboundPacketsLost = 0;
76
- // public totalInboundPacketsReceived = 0;
77
- // public totalOutboundPacketsSent = 0;
78
- // public totalDataChannelBytesSent = 0;
79
- // public totalDataChannelBytesReceived = 0;
80
- // public totalSentBytes = 0;
81
- // public totalReceivedBytes = 0;
82
- // public totalReceivedAudioBytes = 0;
83
- // public totalReceivedVideoBytes = 0;
84
- // public totalSentAudioBytes = 0;
85
- // public totalSentVideoBytes = 0;
86
-
87
- // public deltaReceivedAudioBytes = 0;
88
- // public deltaReceivedVideoBytes = 0;
89
- // public deltaSentAudioBytes = 0;
90
- // public deltaSentVideoBytes = 0;
91
- // public deltaDataChannelBytesSent = 0;
92
- // public deltaDataChannelBytesReceived = 0;
93
- // public deltaInboundPacketsLost = 0;
94
- // public deltaInboundPacketsReceived = 0;
95
- // public deltaOutboundPacketsSent = 0;
96
-
97
- public avgRttInMs?: number;
98
- public outboundAudioBitrate?: number;
99
- public outboundVideoBitrate?: number;
100
- public inboundAudioBitrate?: number;
101
- public inboundVideoBitrate?: number;
81
+
82
+ public totalInboundPacketsLost = 0;
83
+ public totalInboundPacketsReceived = 0;
84
+ public totalOutboundPacketsSent = 0;
85
+ public totalDataChannelBytesSent = 0;
86
+ public totalDataChannelBytesReceived = 0;
87
+ public totalDataChannelMessagesSent = 0;
88
+ public totalDataChannelMessagesReceived = 0;
89
+ public totalReceivedAudioBytes = 0;
90
+ public totalReceivedVideoBytes = 0;
91
+ public totalSentAudioBytes = 0;
92
+ public totalSentVideoBytes = 0;
93
+ public totalSentBytes = 0;
94
+ public totalReceivedBytes = 0;
95
+
96
+ public deltaReceivedAudioBytes = 0;
97
+ public deltaReceivedVideoBytes = 0;
98
+ public deltaSentAudioBytes = 0;
99
+ public deltaSentVideoBytes = 0;
100
+ public deltaDataChannelBytesSent = 0;
101
+ public deltaDataChannelBytesReceived = 0;
102
+ public deltaDataChannelMessagesSent = 0;
103
+ public deltaDataChannelMessagesReceived = 0;
104
+ public deltaInboundPacketsLost = 0;
105
+ public deltaInboundPacketsReceived = 0;
106
+ public deltaOutboundPacketsSent = 0;
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;
102
138
 
103
139
  public readonly mediaDevices: MetaData.MediaDeviceInfo[] = [];
104
140
  public issues: ClientIssue[] = [];
105
141
 
142
+ private _injections: Pick<ClientSample, 'clientEvents' | 'clientIssues' | 'extensionStats' | 'attachments' | 'clientMetaItems'> = {};
143
+
106
144
  public constructor(settings: ObservedClientSettings<AppData>, public readonly call: ObservedCall) {
107
145
  super();
108
146
  this.setMaxListeners(Infinity);
109
147
 
110
148
  this.clientId = settings.clientId;
111
- this.appData = settings.appData;
149
+ this.appData = settings.appData ?? {} as AppData;
150
+
112
151
  this.detectors = new Detectors();
113
152
  }
153
+
154
+ public get numberOfPeerConnections() {
155
+ return this.observedPeerConnections.size;
156
+ }
114
157
 
115
158
  public get score() {
116
159
  return this.calculatedScore.value;
@@ -121,6 +164,14 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
121
164
  this.closed = true;
122
165
 
123
166
  Array.from(this.observedPeerConnections.values()).forEach((peerConnection) => peerConnection.close());
167
+ if (!this.leftAt) {
168
+ this.leftAt = this.lastSampleTimestamp;
169
+
170
+ if (this.leftAt) {
171
+ this.emit('left');
172
+ }
173
+ }
174
+ this.closedAt = Date.now();
124
175
 
125
176
  this.emit('close');
126
177
  }
@@ -129,38 +180,180 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
129
180
  if (this.closed) throw new Error(`Client ${this.clientId} is closed`);
130
181
 
131
182
  const now = Date.now();
183
+ const elapsedInMs = now - this.updated;
184
+ const elapsedInSeconds = elapsedInMs / 1000;
185
+ let sumOfRtts = 0;
186
+ let numberOfRttMeasurements = 0;
187
+
188
+ ++this.acceptedSamples;
189
+
190
+ this.availableIncomingBitrate = 0;
191
+ this.availableOutgoingBitrate = 0;
192
+ this.deltaDataChannelBytesReceived = 0;
193
+ this.deltaDataChannelBytesSent = 0;
194
+ this.deltaDataChannelMessagesReceived = 0;
195
+ this.deltaDataChannelMessagesSent = 0;
196
+ this.deltaInboundPacketsLost = 0;
197
+ this.deltaInboundPacketsReceived = 0;
198
+ this.deltaOutboundPacketsSent = 0;
199
+ this.deltaReceivedAudioBytes = 0;
200
+ this.deltaReceivedVideoBytes = 0;
201
+ this.deltaSentAudioBytes = 0;
202
+ this.deltaSentVideoBytes = 0;
203
+ this.deltaTransportReceivedBytes = 0;
204
+ this.deltaTransportSentBytes = 0;
205
+ this.deltaRttLt50Measurements = 0;
206
+ this.deltaRttLt150Measurements = 0;
207
+ this.deltaRttLt300Measurements = 0;
208
+ this.deltaRttGtOrEq300Measurements = 0;
209
+ this.deltaNumberOfIssues = 0;
210
+
211
+ this.numberOfDataChannels = 0;
212
+ this.numberOfInboundRtpStreams = 0;
213
+ this.numberOfInbundTracks = 0;
214
+ this.numberOfOutboundRtpStreams = 0;
215
+ this.numberOfOutboundTracks = 0;
216
+ this.usingTURN = false;
217
+ this.usingTCP = false;
218
+ this.currentMinRttInMs = undefined;
219
+ this.currentMaxRttInMs = undefined;
220
+
221
+ this._mergeInjections(sample);
222
+
223
+ const clientEventsPostBuffer: ClientEvent[] = [];
224
+
225
+ for (const clientEvent of sample.clientEvents ?? []) {
226
+ this._processClientEvent(clientEvent, clientEventsPostBuffer);
227
+
228
+ this.call.observer.emit('client-event', this, clientEvent);
229
+ }
132
230
 
133
- sample.clientEvents?.forEach(this._processClientEvent.bind(this));
134
- sample.clientMetaItems?.forEach(this.processMetadata.bind(this));
135
- sample.clientIssues?.forEach(this.processIssue.bind(this));
136
- sample.peerConnections?.forEach(this._updatePeerConnection.bind(this));
137
- sample.extensionStats?.forEach(this.processExtensionStats.bind(this));
231
+ for (const metaData of sample.clientMetaItems ?? []) {
232
+ this.addMetadata(metaData);
233
+ }
234
+
235
+ for (const issue of sample.clientIssues ?? []) {
236
+ this.addIssue(issue);
237
+
238
+ ++this.deltaNumberOfIssues;
239
+ }
240
+
241
+ for (const extensionStat of sample.extensionStats ?? []) {
242
+ this.addExtensionStats(extensionStat);
243
+ }
244
+
245
+ for (const pcSample of sample.peerConnections ?? []) {
246
+ const observedPeerConnection = this._updatePeerConnection(pcSample);
247
+
248
+ if (!observedPeerConnection) continue;
249
+
250
+ this.deltaDataChannelBytesReceived += observedPeerConnection.deltaDataChannelBytesReceived;
251
+ this.deltaDataChannelBytesSent += observedPeerConnection.deltaDataChannelBytesSent;
252
+ this.deltaDataChannelMessagesReceived += observedPeerConnection.deltaDataChannelMessagesReceived;
253
+ this.deltaDataChannelMessagesSent += observedPeerConnection.deltaDataChannelMessagesSent;
254
+ this.deltaInboundPacketsLost += observedPeerConnection.deltaInboundPacketsLost;
255
+ this.deltaInboundPacketsReceived += observedPeerConnection.deltaInboundPacketsReceived;
256
+ this.deltaOutboundPacketsSent += observedPeerConnection.deltaOutboundPacketsSent;
257
+ this.deltaReceivedAudioBytes += observedPeerConnection.deltaReceivedAudioBytes;
258
+ this.deltaReceivedVideoBytes += observedPeerConnection.deltaReceivedVideoBytes;
259
+ this.deltaSentAudioBytes += observedPeerConnection.deltaSentAudioBytes;
260
+ this.deltaSentVideoBytes += observedPeerConnection.deltaSentVideoBytes;
261
+ this.deltaTransportReceivedBytes += observedPeerConnection.deltaTransportReceivedBytes;
262
+ this.deltaTransportSentBytes += observedPeerConnection.deltaTransportSentBytes;
263
+
264
+ this.availableIncomingBitrate += observedPeerConnection.availableIncomingBitrate;
265
+ this.availableOutgoingBitrate += observedPeerConnection.availableOutgoingBitrate;
266
+
267
+ this.numberOfDataChannels += observedPeerConnection.observedDataChannels.size;
268
+ this.numberOfInbundTracks += observedPeerConnection.observedInboundTracks.size;
269
+ this.numberOfOutboundRtpStreams += observedPeerConnection.observedOutboundRtps.size;
270
+ this.numberOfOutboundTracks += observedPeerConnection.observedOutboundTracks.size;
271
+ this.numberOfInboundRtpStreams += observedPeerConnection.observedInboundRtps.size;
272
+
273
+ if (observedPeerConnection.usingTURN) {
274
+ this.usingTURN = true;
275
+ }
276
+ if (observedPeerConnection.usingTCP) {
277
+ this.usingTCP = true;
278
+ }
279
+
280
+ if (observedPeerConnection.currentRttInMs) {
281
+ if (this.currentMinRttInMs === undefined || observedPeerConnection.currentRttInMs < this.currentMinRttInMs) {
282
+ this.currentMinRttInMs = observedPeerConnection.currentRttInMs;
283
+ }
284
+ if (this.currentMaxRttInMs === undefined || observedPeerConnection.currentRttInMs > this.currentMaxRttInMs) {
285
+ this.currentMaxRttInMs = observedPeerConnection.currentRttInMs;
286
+ }
287
+ if (observedPeerConnection.currentRttInMs < 50) {
288
+ this.deltaRttLt50Measurements += 1;
289
+ } else if (observedPeerConnection.currentRttInMs < 150) {
290
+ this.deltaRttLt150Measurements += 1;
291
+ } else if (observedPeerConnection.currentRttInMs < 300) {
292
+ this.deltaRttLt300Measurements += 1;
293
+ } else if (300 <= observedPeerConnection.currentRttInMs) {
294
+ this.deltaRttGtOrEq300Measurements += 1;
295
+ }
296
+
297
+ sumOfRtts += observedPeerConnection.currentRttInMs;
298
+ ++numberOfRttMeasurements;
299
+ }
300
+ }
301
+
302
+ for (const clientEvent of clientEventsPostBuffer) {
303
+ this._processClientEvent(clientEvent);
304
+ }
138
305
 
139
306
  // emit new attachments?
140
307
  this.attachments = sample.attachments;
141
308
 
309
+ this.totalDataChannelBytesReceived += this.deltaDataChannelBytesReceived;
310
+ this.totalDataChannelBytesSent += this.deltaDataChannelBytesSent;
311
+ this.totalDataChannelMessagesReceived += this.deltaDataChannelMessagesReceived;
312
+ this.totalDataChannelMessagesSent += this.deltaDataChannelMessagesSent;
313
+ this.totalInboundPacketsLost += this.deltaInboundPacketsLost;
314
+ this.totalInboundPacketsReceived += this.deltaInboundPacketsReceived;
315
+ this.totalOutboundPacketsSent += this.deltaOutboundPacketsSent;
316
+ this.totalReceivedAudioBytes += this.deltaReceivedAudioBytes;
317
+ this.totalReceivedVideoBytes += this.deltaReceivedVideoBytes;
318
+ this.totalSentAudioBytes += this.deltaSentAudioBytes;
319
+ this.totalSentVideoBytes += this.deltaSentVideoBytes;
320
+ this.totalReceivedBytes += this.deltaTransportReceivedBytes;
321
+ this.totalSentBytes += this.deltaTransportSentBytes;
322
+ this.totalRttLt50Measurements += this.deltaRttLt50Measurements;
323
+ this.totalRttLt150Measurements += this.deltaRttLt150Measurements;
324
+ this.totalRttLt300Measurements += this.deltaRttLt300Measurements;
325
+ this.totalRttGtOrEq300Measurements += this.deltaRttGtOrEq300Measurements;
326
+ this.totalNumberOfIssues += this.deltaNumberOfIssues;
327
+
328
+ this.receivingAudioBitrate = (this.deltaReceivedAudioBytes * 8) / (elapsedInSeconds);
329
+ this.receivingVideoBitrate = (this.totalReceivedVideoBytes * 8) / (elapsedInSeconds);
330
+ this.sendingAudioBitrate = (this.deltaSentAudioBytes * 8) / (elapsedInSeconds);
331
+ this.sendingVideoBitrate = (this.deltaSentVideoBytes * 8) / (elapsedInSeconds);
332
+ this.currentAvgRttInMs = 0 < numberOfRttMeasurements ? sumOfRtts / numberOfRttMeasurements : undefined;
333
+
142
334
  this.calculatedScore.value = sample.score;
143
335
  this.detectors.update();
144
336
 
337
+ this.lastSampleTimestamp = sample.timestamp;
145
338
  // emit update
146
339
  this.emit('update', {
147
340
  sample,
148
341
  elapsedTimeInMs: now - this.updated,
149
342
  });
150
343
  this.updated = now;
344
+
345
+ // if result changed after update
346
+ if (this.calculatedScore.value) {
347
+ this.totalScoreSum += this.calculatedScore.value;
348
+ ++this.numberOfScoreMeasurements;
349
+ }
151
350
  }
152
351
 
153
- private _processClientEvent(event: ClientEvent) {
352
+ private _processClientEvent(event: ClientEvent, postBuffer?: ClientEvent[]) {
353
+ // eslint-disable-next-line no-console
354
+ // console.warn('ClientEvent', event);
154
355
  switch (event.type) {
155
- case ClientEventType.CALL_STARTED: {
156
- // update call timestamp if it's the first time
157
- break;
158
- }
159
- case ClientEventType.CALL_ENDED: {
160
- // update call timestamp if it's the first time
161
- break;
162
- }
163
- case ClientEventType.CLIENT_JOINED: {
356
+ case ClientEventTypes.CLIENT_JOINED: {
164
357
  if (event.timestamp) {
165
358
  if (!this.joinedAt) {
166
359
  this.joinedAt = event.timestamp;
@@ -172,78 +365,321 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
172
365
  logger.warn(`Client ${this.clientId} joinedAt timestamp was updated to ${event.timestamp}. the joined event will not be emitted.`);
173
366
  }
174
367
  }
368
+ logger.debug('Client %s joined at %o', this.clientId, event);
175
369
  break;
176
370
  }
177
- case ClientEventType.CLIENT_LEFT: {
371
+ case ClientEventTypes.CLIENT_LEFT: {
178
372
  if (event.timestamp) {
179
373
  if (!this.leftAt) {
180
374
  this.leftAt = event.timestamp;
181
375
  this.emit('left');
376
+ } else {
377
+ logger.warn(`Client ${this.clientId} leftAt timestamp was already set`);
378
+ }
379
+
380
+ }
381
+ logger.debug('Client %s left at %o', this.clientId, event);
382
+ break;
383
+ }
384
+ case ClientEventTypes.PEER_CONNECTION_OPENED: {
385
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
386
+
387
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
388
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
389
+
390
+ if (observedPeerConnection) {
391
+ observedPeerConnection.openedAt = event.timestamp;
392
+ } else if (postBuffer) {
393
+ postBuffer.push(event);
394
+ } else {
395
+ logger.warn('Received PEER_CONNECTION_OPENED event without a corresponding observedPeerConnection: %o', event);
396
+ }
397
+
398
+ }
399
+ break;
400
+ }
401
+ case ClientEventTypes.PEER_CONNECTION_CLOSED: {
402
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
403
+
404
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string') {
405
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
406
+
407
+ if (observedPeerConnection) {
408
+ observedPeerConnection.closedAt = event.timestamp;
409
+ } else if (postBuffer) {
410
+ postBuffer.push(event);
411
+ } else {
412
+ logger.warn('Received PEER_CONNECTION_CLOSED event without a corresponding observedPeerConnection: %o', event);
413
+ }
414
+ }
415
+ break;
416
+ }
417
+ case ClientEventTypes.MEDIA_TRACK_ADDED: {
418
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
419
+
420
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
421
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
422
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
423
+
424
+ if (observedTrack) {
425
+ observedTrack.addedAt = event.timestamp;
426
+ } else if (postBuffer) {
427
+ postBuffer.push(event);
428
+ } else {
429
+ logger.warn('Received MEDIA_TRACK_ADDED event without a corresponding observedPeerConnection or observedTrack: %o', event);
430
+ }
431
+ }
432
+ break;
433
+ }
434
+ case ClientEventTypes.MEDIA_TRACK_REMOVED: {
435
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
436
+
437
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
438
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
439
+ const observedTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId) ?? observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
440
+
441
+ if (observedTrack) {
442
+ observedTrack.removedAt = event.timestamp;
443
+ } else if (postBuffer) {
444
+ postBuffer.push(event);
445
+ } else {
446
+ logger.warn('Received MEDIA_TRACK_REMOVED event without a corresponding observedPeerConnection or observedTrack: %o', event);
447
+ }
448
+ }
449
+ break;
450
+ }
451
+ case ClientEventTypes.DATA_CHANNEL_OPEN: {
452
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
453
+
454
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
455
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
456
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
457
+
458
+ if (observedDataChannel) {
459
+ observedDataChannel.addedAt = event.timestamp;
460
+ } else if (postBuffer) {
461
+ postBuffer.push(event);
462
+ } else {
463
+ logger.warn('Received DATA_CHANNEL_OPENED event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
464
+ }
465
+ }
466
+ break;
467
+ }
468
+ case ClientEventTypes.DATA_CHANNEL_CLOSED: {
469
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
470
+
471
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.dataChannelId && typeof payload.dataChannelId === 'string') {
472
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
473
+ const observedDataChannel = observedPeerConnection?.observedDataChannels.get(payload.dataChannelId);
474
+
475
+ if (observedDataChannel) {
476
+ observedDataChannel.removedAt = event.timestamp;
477
+ } else if (postBuffer) {
478
+ postBuffer.push(event);
479
+ } else {
480
+ logger.warn('Received DATA_CHANNEL_CLOSE event without a corresponding observedPeerConnection or observedDataChannel: %o', event);
481
+ }
482
+ }
483
+ break;
484
+ }
485
+ case ClientEventTypes.MEDIA_TRACK_MUTED: {
486
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
487
+
488
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
489
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
490
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
491
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
492
+
493
+ if (observedPeerConnection) {
494
+ if (observedInboundTrack) {
495
+ observedInboundTrack.muted = true;
496
+ observedPeerConnection?.emit('muted-inbound-track', observedInboundTrack);
497
+ } else if (observedOutboundTrack) {
498
+ observedOutboundTrack.muted = true;
499
+ observedPeerConnection?.emit('muted-outbound-track', observedOutboundTrack);
500
+ }
501
+ } else if (postBuffer) {
502
+ postBuffer.push(event);
503
+ } else {
504
+ logger.warn('Received MEDIA_TRACK_MUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
505
+ }
506
+ }
507
+
508
+ break;
509
+ }
510
+ case ClientEventTypes.MEDIA_TRACK_UNMUTED: {
511
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
512
+
513
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.trackId && typeof payload.trackId === 'string') {
514
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
515
+ const observedInboundTrack = observedPeerConnection?.observedInboundTracks.get(payload.trackId);
516
+ const observedOutboundTrack = observedPeerConnection?.observedOutboundTracks.get(payload.trackId);
517
+
518
+ if (observedPeerConnection) {
519
+ if (observedInboundTrack) {
520
+ observedInboundTrack.muted = false;
521
+ observedPeerConnection?.emit('unmuted-inbound-track', observedInboundTrack);
522
+ } else if (observedOutboundTrack) {
523
+ observedOutboundTrack.muted = false;
524
+ observedPeerConnection?.emit('unmuted-outbound-track', observedOutboundTrack);
525
+ }
526
+ } else if (postBuffer) {
527
+ postBuffer.push(event);
528
+ } else {
529
+ logger.warn('Received MEDIA_TRACK_UNMUTED event without a corresponding observedPeerConnection or observedTrack: %o', event);
530
+ }
531
+ }
532
+ break;
533
+ }
534
+ case ClientEventTypes.ICE_CONNECTION_STATE_CHANGED: {
535
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
536
+
537
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceConnectionState && typeof payload.iceConnectionState === 'string') {
538
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
539
+
540
+ if (observedPeerConnection) {
541
+ observedPeerConnection.iceConnectionState = payload.iceConnectionState;
542
+ observedPeerConnection.emit('iceconnectionstatechange', {
543
+ state: payload.iceConnectionState,
544
+ });
545
+ } else if (postBuffer) {
546
+ postBuffer.push(event);
547
+ } else {
548
+ logger.warn('Received ICE_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
549
+ }
550
+ }
551
+ break;
552
+ }
553
+ case ClientEventTypes.ICE_GATHERING_STATE_CHANGED: {
554
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
555
+
556
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.iceGatheringState && typeof payload.iceGatheringState === 'string') {
557
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
558
+
559
+ if (observedPeerConnection) {
560
+ observedPeerConnection.iceGatheringState = payload.iceGatheringState;
561
+ observedPeerConnection.emit('icegatheringstatechange', {
562
+ state: payload.iceGatheringState,
563
+ });
564
+ } else if (postBuffer) {
565
+ postBuffer.push(event);
566
+ } else {
567
+ logger.warn('Received ICE_GATHERING_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
568
+ }
569
+ }
570
+ break;
571
+ }
572
+ case ClientEventTypes.PEER_CONNECTION_STATE_CHANGED: {
573
+ const payload = parseJsonAs<Record<string, unknown>>(event.payload);
574
+
575
+ if (payload?.peerConnectionId && typeof payload.peerConnectionId === 'string' && payload?.peerConnectionState && typeof payload.peerConnectionState === 'string') {
576
+ const observedPeerConnection = this.observedPeerConnections.get(payload.peerConnectionId);
577
+
578
+ if (observedPeerConnection) {
579
+ observedPeerConnection.connectionState = payload.peerConnectionState;
580
+ observedPeerConnection.emit('connectionstatechange', {
581
+ state: payload.peerConnectionState,
582
+ });
583
+ } else if (postBuffer) {
584
+ postBuffer.push(event);
585
+ } else {
586
+ logger.warn('Received PEER_CONNECTION_STATE_CHANGED event without a corresponding observedPeerConnection: %o', event);
182
587
  }
183
588
  }
184
589
  break;
185
590
  }
186
591
  }
592
+
593
+ this.emit('clientEvent', event);
594
+ }
187
595
 
188
- this.call.observer.processors.events.process({
189
- call: this.call,
190
- client: this,
191
- data: event,
192
- });
596
+ public injectMetaData(metaData: ClientMetaData) {
597
+ if (this.closed) return;
598
+
599
+ if (!this._injections.clientMetaItems) this._injections.clientMetaItems = [];
600
+
601
+ this._injections.clientMetaItems.push(metaData);
602
+ }
603
+
604
+ public injectEvent(event: ClientEvent) {
605
+ if (this.closed) return;
606
+
607
+ if (!this._injections.clientEvents) this._injections.clientEvents = [];
608
+
609
+ this._injections.clientEvents.push(event);
193
610
  }
194
611
 
195
- public processMetadata(metadata: ClientMetaData) {
612
+ public injectIssue(issue: ClientIssue) {
613
+ if (this.closed) return;
614
+
615
+ if (!this._injections.clientIssues) this._injections.clientIssues = [];
616
+
617
+ this._injections.clientIssues.push(issue);
618
+ }
619
+
620
+ public injectExtensionStat(stat: ExtensionStat) {
621
+ if (this.closed) return;
622
+
623
+ if (!this._injections.extensionStats) this._injections.extensionStats = [];
624
+
625
+ this._injections.extensionStats.push(stat);
626
+ }
627
+
628
+ public injectAttachment(key: string, value: unknown) {
629
+ if (this.closed) return;
630
+
631
+ if (!this._injections.attachments) this._injections.attachments = {};
632
+
633
+ this._injections.attachments[key] = value;
634
+
635
+ }
636
+
637
+ public addMetadata(metadata: ClientMetaData) {
638
+ if (this.closed) return;
639
+
196
640
  switch (metadata.type) {
197
- case ClientMetaType.BROWSER: {
641
+ case ClientMetaTypes.BROWSER: {
198
642
  this.browser = parseJsonAs(metadata.payload);
199
643
  break;
200
644
  }
201
- case ClientMetaType.ENGINE: {
645
+ case ClientMetaTypes.ENGINE: {
202
646
  this.engine = parseJsonAs(metadata.payload);
203
647
  break;
204
648
  }
205
- case ClientMetaType.PLATFORM: {
649
+ case ClientMetaTypes.PLATFORM: {
206
650
  this.platform = parseJsonAs(metadata.payload);
207
651
  break;
208
652
  }
209
- case ClientMetaType.OPERATION_SYSTEM: {
653
+ case ClientMetaTypes.OPERATION_SYSTEM: {
210
654
  this.operationSystem = parseJsonAs(metadata.payload);
211
655
  break;
212
656
  }
213
657
  }
214
658
 
215
- this.call.observer.processors.metaData.process({
216
- call: this.call,
217
- client: this,
218
- data: metadata,
219
- });
659
+ this.call.observer.emit('client-metadata', this, metadata);
220
660
  }
221
661
 
222
- public processIssue(issue: ClientIssue) {
223
- this.call.observer.processors.issues.process({
224
- call: this.call,
225
- client: this,
226
- data: issue,
227
- });
662
+ public addIssue(issue: ClientIssue) {
663
+ if (this.closed) return;
664
+
665
+ this.emit('issue', issue);
666
+ this.call.observer.emit('client-issue', this, issue);
228
667
  }
229
668
 
230
- public processExtensionStats(stats: ExtensionStat) {
231
- this.call.observer.processors.extensionStats.process({
232
- call: this.call,
233
- client: this,
234
- data: stats,
235
- });
669
+ public addExtensionStats(stats: ExtensionStat) {
670
+ this.call.observer.emit('client-extension-stats', this, stats);
671
+ this.emit('extensionStats', stats);
236
672
  }
237
673
 
238
- private _updatePeerConnection(sample: PeerConnectionSample) {
674
+ private _updatePeerConnection(sample: PeerConnectionSample): ObservedPeerConnection | undefined {
239
675
  let observedPeerConnection = this.observedPeerConnections.get(sample.peerConnectionId);
240
676
 
241
677
  if (!observedPeerConnection) {
242
678
  if (!sample.peerConnectionId) {
243
- return logger.warn(
679
+ return (logger.warn(
244
680
  `ObservedClient received an invalid PeerConnectionSample (missing peerConnectionId field). ClientId: ${this.clientId}, CallId: ${this.call.callId}`,
245
681
  sample
246
- );
682
+ ), void 0);
247
683
  }
248
684
 
249
685
  observedPeerConnection = new ObservedPeerConnection(sample.peerConnectionId, this);
@@ -252,8 +688,101 @@ export class ObservedClient<AppData extends Record<string, unknown> = Record<str
252
688
  this.observedPeerConnections.delete(sample.peerConnectionId);
253
689
  });
254
690
  this.observedPeerConnections.set(sample.peerConnectionId, observedPeerConnection);
691
+
692
+ this.emit('newpeerconnection', observedPeerConnection);
255
693
  }
256
694
 
257
695
  observedPeerConnection.accept(sample);
696
+
697
+ return observedPeerConnection;
698
+ }
699
+
700
+ private _mergeInjections(sample: ClientSample): ClientSample {
701
+ if (this.closed) return sample;
702
+
703
+ if (this._injections.clientEvents) {
704
+ if (!sample.clientEvents) sample.clientEvents = [];
705
+ sample.clientEvents.push(...this._injections.clientEvents);
706
+
707
+ this._injections.clientEvents = undefined;
708
+ }
709
+
710
+ if (this._injections.clientIssues) {
711
+ if (!sample.clientIssues) sample.clientIssues = [];
712
+ sample.clientIssues.push(...this._injections.clientIssues);
713
+
714
+ this._injections.clientIssues = undefined;
715
+ }
716
+
717
+ if (this._injections.extensionStats) {
718
+ if (!sample.extensionStats) sample.extensionStats = [];
719
+ sample.extensionStats.push(...this._injections.extensionStats);
720
+
721
+ this._injections.extensionStats = undefined;
722
+ }
723
+
724
+ if (this._injections.attachments) {
725
+ if (!sample.attachments) sample.attachments = {};
726
+ Object.assign(sample.attachments, this._injections.attachments);
727
+
728
+ this._injections.attachments = undefined;
729
+ }
730
+
731
+ if (this._injections.clientMetaItems) {
732
+ if (!sample.clientMetaItems) sample.clientMetaItems = [];
733
+ sample.clientMetaItems.push(...this._injections.clientMetaItems);
734
+
735
+ this._injections.clientMetaItems = undefined;
736
+ }
737
+
738
+ return sample;
258
739
  }
740
+
741
+ // public resetSummaryMetrics() {
742
+ // this.totalDataChannelBytesReceived = 0;
743
+ // this.totalDataChannelBytesSent = 0;
744
+ // this.totalDataChannelMessagesReceived = 0;
745
+ // this.totalDataChannelMessagesSent = 0;
746
+ // this.totalInboundPacketsLost = 0;
747
+ // this.totalInboundPacketsReceived = 0;
748
+ // this.totalOutboundPacketsSent = 0;
749
+ // this.totalReceivedAudioBytes = 0;
750
+ // this.totalReceivedVideoBytes = 0;
751
+ // this.totalSentAudioBytes = 0;
752
+ // this.totalSentVideoBytes = 0;
753
+ // this.totalSentBytes = 0;
754
+ // this.totalReceivedBytes = 0;
755
+
756
+ // this.totalNumberOfIssues = 0;
757
+
758
+ // this.totalScoreSum = 0;
759
+ // this.numberOfScoreMeasurements = 0;
760
+ // }
761
+
762
+ // public createSummary(): ObservedClientSummary {
763
+ // return {
764
+ // totalRttLt50Measurements: this.totalRttLt50Measurements,
765
+ // totalRttLt150Measurements: this.totalRttLt150Measurements,
766
+ // totalRttLt300Measurements: this.totalRttLt300Measurements,
767
+ // totalRttGtOrEq300Measurements: this.totalRttGtOrEq300Measurements,
768
+ // totalDataChannelBytesReceived: this.totalDataChannelBytesReceived,
769
+ // totalDataChannelBytesSent: this.totalDataChannelBytesSent,
770
+ // totalDataChannelMessagesReceived: this.totalDataChannelMessagesReceived,
771
+ // totalDataChannelMessagesSent: this.totalDataChannelMessagesSent,
772
+ // totalInboundPacketsLost: this.totalInboundPacketsLost,
773
+ // totalInboundPacketsReceived: this.totalInboundPacketsReceived,
774
+ // totalOutboundPacketsSent: this.totalOutboundPacketsSent,
775
+ // totalReceivedAudioBytes: this.totalReceivedAudioBytes,
776
+ // totalReceivedVideoBytes: this.totalReceivedVideoBytes,
777
+ // totalSentAudioBytes: this.totalSentAudioBytes,
778
+ // totalSentVideoBytes: this.totalSentVideoBytes,
779
+ // totalSentBytes: this.totalSentBytes,
780
+ // totalReceivedBytes: this.totalReceivedBytes,
781
+
782
+ // numberOfIssues: this.totalNumberOfIssues,
783
+
784
+ // totalScoreSum: this.totalScoreSum,
785
+ // numberOfScoreMeasurements: this.numberOfScoreMeasurements,
786
+ // };
787
+ // }
259
788
  }