@flashphoner/websdk 2.0.262 → 2.0.264

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flashphoner/websdk",
3
- "version": "2.0.262",
3
+ "version": "2.0.264",
4
4
  "description": "Official Flashphoner WebCallServer WebSDK package",
5
5
  "main": "./src/flashphoner-core.js",
6
6
  "types": "./src/flashphoner-core.d.ts",
@@ -20,7 +20,6 @@
20
20
  "chai": "^3.5.0",
21
21
  "grunt": "^1.0.1",
22
22
  "grunt-browserify": "^5.0.0",
23
- "grunt-contrib": "^0.11.0",
24
23
  "grunt-contrib-clean": "^1.0.0",
25
24
  "grunt-contrib-concat": "^1.0.1",
26
25
  "grunt-contrib-copy": "^1.0.0",
@@ -16,6 +16,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
16
16
  metricsBatch: null,
17
17
  timer: null,
18
18
  batchCount: 0,
19
+ timerBusy: false,
19
20
  start: async function() {
20
21
  let error = "Can't collect WebRTC stats to send: ";
21
22
  if (!statCollector.description.types) {
@@ -55,7 +56,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
55
56
  update: async function(description) {
56
57
  if (!description) {
57
58
  if (statCollector.logger) {
58
- statCollector.logger.error(LOG_PREFIX, "Can't update WebRTC metrics sending: no parameters passed");
59
+ statCollector.logger.error(LOG_PREFIX + "-" + statCollector.id, "Can't update WebRTC metrics sending: no parameters passed");
59
60
  return;
60
61
  }
61
62
  }
@@ -91,8 +92,12 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
91
92
  break;
92
93
  }
93
94
  },
94
- updateHeaders: async function() {
95
- let stats = await statCollector.mediaConnection.getWebRTCStats();
95
+ updateHeaders: async function(stats = null) {
96
+ let currentHeaders = "";
97
+ let headersChanged = false;
98
+ if (!stats) {
99
+ stats = await statCollector.mediaConnection.getWebRTCStats();
100
+ }
96
101
  Object.keys(statCollector.description.types).forEach((type) => {
97
102
  let typeDescriptor = statCollector.description.types[type];
98
103
  let metricsString = "";
@@ -105,15 +110,15 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
105
110
  }
106
111
  if (stats[type]) {
107
112
  stats[type].forEach((report) => {
108
- statCollector.logger.debug(LOG_PREFIX, type + " report: " + JSON.stringify(report));
113
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, type + " report: " + JSON.stringify(report));
109
114
  if (contentFilters) {
110
115
  let filtersMatched = true;
111
116
  for (const filter in contentFilters) {
112
- statCollector.logger.debug(LOG_PREFIX, type + " filter by " + filter + ": " + JSON.stringify(contentFilters[filter]));
117
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, type + " filter by " + filter + ": " + JSON.stringify(contentFilters[filter]));
113
118
  let filterMatched = false;
114
119
  if (report[filter]) {
115
120
  for (const value of contentFilters[filter]) {
116
- statCollector.logger.debug(LOG_PREFIX, filter + ": " + value + " <> " + report[filter]);
121
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, filter + ": " + value + " <> " + report[filter]);
117
122
  if (report[filter] === value) {
118
123
  filterMatched = true;
119
124
  break;
@@ -126,34 +131,44 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
126
131
  }
127
132
  }
128
133
  if (filtersMatched) {
129
- statCollector.addHeaders(report, metricsString);
134
+ currentHeaders = statCollector.addHeaders(currentHeaders, report, metricsString);
130
135
  }
131
136
  } else {
132
- statCollector.addHeaders(report, metricsString);
137
+ currentHeaders = statCollector.addHeaders(currentHeaders, report, metricsString);
133
138
  }
134
139
  });
135
140
  } else {
136
- statCollector.logger.warn(LOG_PREFIX, "No report type found in RTC stats: '" + type + "'");
141
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, "No report type found in RTC stats: '" + type + "'");
137
142
  }
138
143
  });
144
+ if (currentHeaders !== statCollector.headers) {
145
+ headersChanged = true;
146
+ let newMetrics = [];
147
+ currentHeaders.split(",").forEach((header) => {
148
+ if (statCollector.headers.indexOf(header) === -1) {
149
+ newMetrics.push(header);
150
+ }
151
+ });
152
+ if (newMetrics.length) {
153
+ statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "RTC metrics to be collected: " + newMetrics.toString());
154
+ }
155
+ statCollector.headers = currentHeaders;
156
+ }
157
+ return headersChanged;
139
158
  },
140
- addHeaders: function(report, metricsString) {
159
+ addHeaders: function(currentHeaders, report, metricsString) {
141
160
  if (metricsString) {
142
161
  let metrics = metricsString.split(",");
143
162
  metrics.forEach((metric) => {
144
- let metricFound = false;
145
163
  for (const key of Object.keys(report)) {
146
164
  if (metric === key) {
147
- statCollector.headers = util.addFieldToCsvString(statCollector.headers, report.type + "." + report.id + "." + metric, ",");
148
- metricFound = true;
165
+ currentHeaders = util.addFieldToCsvString(currentHeaders, report.type + "." + report.id + "." + metric, ",");
149
166
  break;
150
167
  }
151
168
  }
152
- if (!metricFound) {
153
- statCollector.logger.warn(LOG_PREFIX, "No metric found in RTC stats report '" + report.type + "': '" + metric + "'");
154
- }
155
169
  });
156
170
  }
171
+ return currentHeaders;
157
172
  },
158
173
  updateCompression: async function() {
159
174
  if (statCollector.description.compression) {
@@ -169,7 +184,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
169
184
  await util.compress(compression, "test", false);
170
185
  statCollector.compression = compression;
171
186
  } catch (e) {
172
- statCollector.logger.warn(LOG_PREFIX, "Can't compress metrics data using " + compression + ": " + e);
187
+ statCollector.logger.warn(LOG_PREFIX + "-" + statCollector.id, "Can't compress metrics data using " + compression + ": " + e);
173
188
  statCollector.compression = "none";
174
189
  }
175
190
  },
@@ -182,7 +197,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
182
197
  statCollector.send("webRTCMetricsClientDescription", data);
183
198
  },
184
199
  send: function(message, data) {
185
- statCollector.logger.debug(LOG_PREFIX, data);
200
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, data);
186
201
  if (statCollector.wsConnection.readyState === WebSocket.OPEN) {
187
202
  statCollector.wsConnection.send(JSON.stringify({
188
203
  message: message,
@@ -204,14 +219,16 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
204
219
  }
205
220
  },
206
221
  collectMetrics: async function() {
207
- if (statCollector.timer) {
222
+ if (statCollector.timer && !statCollector.timerBusy) {
223
+ // Unfortunately there are no real atomics in JS unless SharedArrayBuffer is used
224
+ // So we guard the timer callback with a dumb boolean
225
+ statCollector.timerBusy = true;
208
226
  let stats = await statCollector.mediaConnection.getWebRTCStats();
209
227
 
210
- if (!statCollector.metricsBatch) {
211
- statCollector.metricsBatch = [];
212
- }
228
+ statCollector.startNewBatch();
213
229
 
214
230
  let metrics = [];
231
+ let lostMetrics = [];
215
232
  statCollector.headers.split(",").forEach((header) => {
216
233
  let components = header.split(".");
217
234
  let descriptor = {
@@ -219,7 +236,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
219
236
  id: components[1],
220
237
  name: components[2]
221
238
  }
222
- let value = "undefined";
239
+ let value = null;
223
240
 
224
241
  if (stats[descriptor.type]) {
225
242
  for (const report of stats[descriptor.type]) {
@@ -229,13 +246,32 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
229
246
  }
230
247
  }
231
248
  }
232
- metrics.push(value);
249
+ if (value === null) {
250
+ lostMetrics.push(descriptor);
251
+ } else {
252
+ metrics.push(value);
253
+ }
233
254
  });
234
- statCollector.metricsBatch.push(metrics);
235
- statCollector.batchCount--;
236
- if (statCollector.batchCount === 0) {
255
+ // Metrics list may change if some metrics are added or some metrics are lost #WCS-4627
256
+ let headersUpdated = await statCollector.updateHeaders(stats);
257
+ if (lostMetrics.length) {
258
+ statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "Missing metrics: " + JSON.stringify(lostMetrics));
259
+ // Send metrics already collected and start a new batch with current metrics array to send them later #WCS-4627
237
260
  await statCollector.sendMetrics();
261
+ statCollector.startNewBatch(metrics);
262
+ } else {
263
+ statCollector.metricsBatch.push(metrics);
264
+ statCollector.batchCount--;
265
+ if (statCollector.batchCount === 0 || headersUpdated) {
266
+ await statCollector.sendMetrics();
267
+ }
268
+ }
269
+ // Check if metrics list changed and send a new headers if needed #WCS-4619
270
+ if (headersUpdated) {
271
+ statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "RTC metrics list has changed, sending a new metrics description");
272
+ statCollector.sendHeaders();
238
273
  }
274
+ statCollector.timerBusy = false;
239
275
  }
240
276
  },
241
277
  sendMetrics: async function() {
@@ -243,7 +279,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
243
279
  let metricsToSend = [];
244
280
  let metricsData;
245
281
 
246
- for (let i = 0; i < statCollector.metricsBatch.length; i++) {
282
+ for (let i = 0; statCollector.metricsBatch && i < statCollector.metricsBatch.length; i++) {
247
283
  let metricsString = "";
248
284
  for (let j = 0; j < statCollector.metricsBatch[i].length; j++) {
249
285
  let valueString = valueToString(statCollector.metricsBatch[i][j]);
@@ -267,7 +303,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
267
303
  try {
268
304
  metricsData = await util.compress(statCollector.compression, JSON.stringify(metricsToSend), true);
269
305
  } catch(e) {
270
- statCollector.logger.warn(LOG_PREFIX, "Can't send metrics data using" + statCollector.compression + ": " + e);
306
+ statCollector.logger.warn(LOG_PREFIX + "-" + statCollector.id, "Can't send metrics data using" + statCollector.compression + ": " + e);
271
307
  metricsData = null;
272
308
  }
273
309
  } else {
@@ -280,8 +316,21 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
280
316
  };
281
317
  statCollector.send("webRTCMetricsBatch", data);
282
318
  }
283
- statCollector.metricsBatch = null;
284
- statCollector.batchCount = statCollector.description.batchSize;
319
+ statCollector.cleanBatch();
320
+ },
321
+ startNewBatch: function(metrics) {
322
+ if (!statCollector.metricsBatch) {
323
+ statCollector.metricsBatch = [];
324
+ if (metrics) {
325
+ statCollector.metricsBatch.push(metrics);
326
+ }
327
+ }
328
+ },
329
+ cleanBatch: function() {
330
+ if (statCollector.metricsBatch) {
331
+ statCollector.metricsBatch = null;
332
+ statCollector.batchCount = statCollector.description.batchSize;
333
+ }
285
334
  }
286
335
  }
287
336
  return statCollector;