@flashphoner/websdk 2.0.261 → 2.0.263

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.261",
3
+ "version": "2.0.263",
4
4
  "description": "Official Flashphoner WebCallServer WebSDK package",
5
5
  "main": "./src/flashphoner-core.js",
6
6
  "types": "./src/flashphoner-core.d.ts",
@@ -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,7 +219,10 @@ 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
228
  if (!statCollector.metricsBatch) {
@@ -212,6 +230,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
212
230
  }
213
231
 
214
232
  let metrics = [];
233
+ let lostMetrics = [];
215
234
  statCollector.headers.split(",").forEach((header) => {
216
235
  let components = header.split(".");
217
236
  let descriptor = {
@@ -219,7 +238,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
219
238
  id: components[1],
220
239
  name: components[2]
221
240
  }
222
- let value = "undefined";
241
+ let value = "NO";
223
242
 
224
243
  if (stats[descriptor.type]) {
225
244
  for (const report of stats[descriptor.type]) {
@@ -230,12 +249,25 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
230
249
  }
231
250
  }
232
251
  metrics.push(value);
252
+ if (value == "NO") {
253
+ lostMetrics.push(descriptor);
254
+ }
233
255
  });
256
+ if (lostMetrics.length) {
257
+ statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "Missing metrics: " + JSON.stringify(lostMetrics));
258
+ }
234
259
  statCollector.metricsBatch.push(metrics);
235
260
  statCollector.batchCount--;
236
261
  if (statCollector.batchCount === 0) {
237
262
  await statCollector.sendMetrics();
238
263
  }
264
+ // Check if metrics list changed and send a new headers if needed #WCS-4619
265
+ if (await statCollector.updateHeaders(stats)) {
266
+ statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "RTC metrics list has changed, sending a new metrics description");
267
+ await statCollector.sendMetrics();
268
+ statCollector.sendHeaders();
269
+ }
270
+ statCollector.timerBusy = false;
239
271
  }
240
272
  },
241
273
  sendMetrics: async function() {
@@ -248,14 +280,17 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
248
280
  for (let j = 0; j < statCollector.metricsBatch[i].length; j++) {
249
281
  let valueString = valueToString(statCollector.metricsBatch[i][j]);
250
282
  let previousString = "";
251
- let separator = ";";
283
+ let delimiter = ";";
252
284
  if (previous) {
253
285
  previousString = valueToString(previous[j]);
254
286
  }
255
287
  if (valueString === previousString) {
256
288
  valueString = "";
257
289
  }
258
- metricsString = util.addFieldToCsvString(metricsString, valueString, separator);
290
+ metricsString = util.addFieldToCsvString(metricsString, valueString, delimiter);
291
+ if (j > 0 && metricsString === "") {
292
+ metricsString = delimiter;
293
+ }
259
294
  }
260
295
  previous = statCollector.metricsBatch[i];
261
296
  metricsToSend.push(metricsString);
@@ -264,7 +299,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
264
299
  try {
265
300
  metricsData = await util.compress(statCollector.compression, JSON.stringify(metricsToSend), true);
266
301
  } catch(e) {
267
- statCollector.logger.warn(LOG_PREFIX, "Can't send metrics data using" + statCollector.compression + ": " + e);
302
+ statCollector.logger.warn(LOG_PREFIX + "-" + statCollector.id, "Can't send metrics data using" + statCollector.compression + ": " + e);
268
303
  metricsData = null;
269
304
  }
270
305
  } else {
package/src/util.js CHANGED
@@ -490,14 +490,14 @@ const setPublishingBitrate = function(sdp, mediaConnection, minBitrate, maxBitra
490
490
  return sdp;
491
491
  };
492
492
 
493
- const addFieldToCsvString = function(csvString, field, separator) {
494
- if (field !== "" && field.indexOf(separator) >= 0 ) {
493
+ const addFieldToCsvString = function(csvString, field, delimiter) {
494
+ if (field !== "" && field.indexOf(delimiter) >= 0 ) {
495
495
  field = '"' + field + '"';
496
496
  }
497
- if (csvString === "" && field !== "") {
497
+ if (csvString === "") {
498
498
  csvString = field;
499
499
  } else {
500
- csvString = csvString + separator + field;
500
+ csvString = csvString + delimiter + field;
501
501
  }
502
502
  return csvString;
503
503
  }