@flashphoner/websdk 2.0.271 → 2.0.274

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.271",
3
+ "version": "2.0.274",
4
4
  "description": "Official Flashphoner WebCallServer WebSDK package",
5
5
  "main": "./src/flashphoner-core.js",
6
6
  "types": "./src/flashphoner-core.d.ts",
@@ -293,6 +293,34 @@ var getMediaDevices = function (mediaProvider, labels, kind, deviceConstraints)
293
293
  return MediaProvider[mediaProvider].listDevices(labels, kind, deviceConstraints);
294
294
  };
295
295
 
296
+ /**
297
+ * Get mobile local media devices
298
+ *
299
+ * @param {String=} mediaProvider Media provider that will be asked for device list
300
+ * @param {Flashphoner.constants.MEDIA_DEVICE_KIND} kind Media devices kind to access:
301
+ * MEDIA_DEVICE_KIND.INPUT (default) get access to input devices only (camera, mic).
302
+ * MEDIA_DEVICE_KIND.OUTPUT get access to output devices only (speaker, headphone).
303
+ * MEDIA_DEVICE_KIND.ALL get access to all devices (cam, mic, speaker, headphone).
304
+ * @param {Object=} deviceConstraints
305
+ * If {audio: true, video: false}, then access to the camera will not be requested.
306
+ * If {audio: false, video: true}, then access to the microphone will not be requested.
307
+ * @returns {Promise.<Flashphoner.MediaDeviceList>} Promise with media device list on fulfill
308
+ * @throws {Error} Error if API is not initialized
309
+ * @memberof Flashphoner
310
+ */
311
+ var getMobileDevices = function (mediaProvider, kind, deviceConstraints) {
312
+ if (!initialized) {
313
+ throw new Error("Flashphoner API is not initialized");
314
+ }
315
+ if (!mediaProvider) {
316
+ mediaProvider = getMediaProviders()[0];
317
+ }
318
+ if (MediaProvider[mediaProvider].getMobileDevices) {
319
+ return MediaProvider[mediaProvider].getMobileDevices(kind, deviceConstraints);
320
+ }
321
+ return [];
322
+ };
323
+
296
324
  /**
297
325
  * Get access to local media
298
326
  *
@@ -730,33 +758,19 @@ var createSession = function (options) {
730
758
  streamRefreshHandlers[obj.mediaSessionId](obj);
731
759
  }
732
760
  break;
733
- case `webRTCMetricsDescriptionUpdate`:
734
- if (obj.ids) {
735
- obj.ids.forEach((id) => {
736
- if (streamRefreshHandlers[id]) {
737
- streamRefreshHandlers[id](obj);
738
- }
739
- });
740
- } else {
741
- if (obj.compression) {
742
- webRTCMetricsServerDescription.compression = obj.compression;
743
- }
744
- if (obj.batchSize) {
745
- webRTCMetricsServerDescription.batchSize = obj.batchSize;
746
- }
747
- if (obj.sampling) {
748
- webRTCMetricsServerDescription.sampling = obj.sampling;
749
- }
750
- if (obj.types) {
751
- webRTCMetricsServerDescription.types = obj.types;
752
- }
753
- if (obj.collect) {
754
- webRTCMetricsServerDescription.collect = obj.collect;
755
- }
756
- for (const [id, handler] of Object.entries(streamRefreshHandlers)) {
757
- handler(obj);
758
- }
759
- }
761
+ case 'webRTCMetricsDescriptionUpdate':
762
+ handleWebRTCMetricsUpdate(obj, {
763
+ compression: "compression",
764
+ batchSize: "batchSize",
765
+ sampling: "sampling",
766
+ types: "types",
767
+ collect: "collect"
768
+ });
769
+ break;
770
+ case 'webRTCMetricsTokenRefresh':
771
+ handleWebRTCMetricsUpdate(obj, {
772
+ authorization: "authorization"
773
+ });
760
774
  break;
761
775
  default:
762
776
  logger.info(LOG_PREFIX, "Unknown server message " + data.message);
@@ -767,6 +781,26 @@ var createSession = function (options) {
767
781
  };
768
782
  }
769
783
 
784
+ function handleWebRTCMetricsUpdate(obj, updateFields = {}) {
785
+ if (obj.ids) {
786
+ obj.ids.forEach((id) => {
787
+ if (streamRefreshHandlers[id]) {
788
+ streamRefreshHandlers[id](obj);
789
+ }
790
+ });
791
+ } else {
792
+ Object.entries(updateFields).forEach(([key, value]) => {
793
+ if (obj[value] !== undefined) {
794
+ webRTCMetricsServerDescription[key] = obj[value];
795
+ }
796
+ });
797
+
798
+ for (const [id, handler] of Object.entries(streamRefreshHandlers)) {
799
+ handler(obj);
800
+ }
801
+ }
802
+ }
803
+
770
804
  //WebSocket send helper
771
805
  function send(message, data) {
772
806
  if (wsConnection.readyState === WebSocket.OPEN) {
@@ -1920,6 +1954,11 @@ var createSession = function (options) {
1920
1954
  }
1921
1955
  }
1922
1956
 
1957
+ if (streamInfo.authorization && statsCollector && statsCollector.description.ingestPoint) {
1958
+ statsCollector.description.authorization = streamInfo.authorization;
1959
+ statsCollector.updateHttpConnection(statsCollector.description.ingestPoint, statsCollector.description.authorization);
1960
+ }
1961
+
1923
1962
  // Pause or resume metrics collection
1924
1963
  if (!streamInfo.status && streamInfo.collect !== undefined && statsCollector) {
1925
1964
  statsCollector.update(streamInfo);
@@ -3140,6 +3179,7 @@ module.exports = {
3140
3179
  isUsingTemasys: isUsingTemasys,
3141
3180
  getMediaProviders: getMediaProviders,
3142
3181
  getMediaDevices: getMediaDevices,
3182
+ getMobileDevices: getMobileDevices,
3143
3183
  getMediaAccess: getMediaAccess,
3144
3184
  releaseLocalMedia: releaseLocalMedia,
3145
3185
  getSessions: getSessions,
@@ -200,6 +200,11 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
200
200
  }
201
201
  }
202
202
  },
203
+ updateHttpConnection: function(url, authorization) {
204
+ if (url.startsWith(CONNECTION_TYPE.HTTP) && authorization) {
205
+ statCollector.connection.http.setAuthorization(authorization);
206
+ }
207
+ },
203
208
  checkForCompression: async function(compression) {
204
209
  try {
205
210
  await util.compress(compression, "test", false);
@@ -240,6 +245,9 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
240
245
  statCollector.metricsBatch = null;
241
246
  }
242
247
  },
248
+ isMetricValid: function(value) {
249
+ return value != null && value !== "" && value !== "undefined" && value !== "null";
250
+ },
243
251
  collectMetrics: async function() {
244
252
  if (statCollector.timer && !statCollector.timerBusy) {
245
253
  // Unfortunately there are no real atomics in JS unless SharedArrayBuffer is used
@@ -269,7 +277,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
269
277
  }
270
278
  }
271
279
  }
272
- if (value) {
280
+ if (statCollector.isMetricValid(value)) {
273
281
  metrics.push(value);
274
282
  } else {
275
283
  lostMetrics.push(descriptor);
@@ -443,6 +451,9 @@ const HttpConnection = function(url, headers) {
443
451
  const connection = {
444
452
  url: addSlash(url),
445
453
  headers: headers,
454
+ setAuthorization(token) {
455
+ this.headers.Authorization = token;
456
+ },
446
457
  send: async function(message, data) {
447
458
  let code = CONNECTION_STATUS.BAD_REQUEST;
448
459
  if (connection.url) {
@@ -1552,6 +1552,63 @@ var available = function () {
1552
1552
  return ('getUserMedia' in navigator && 'RTCPeerConnection' in window);
1553
1553
  };
1554
1554
 
1555
+ /**
1556
+ * Helper function to get media devices list in id, label, type form
1557
+ *
1558
+ * @param devices
1559
+ * @param kind
1560
+ * @param videoFilter
1561
+ * @returns {{audio: *[], video: *[]}}
1562
+ */
1563
+ const getList = function (devices, kind, videoFilter = null) {
1564
+ var list = {
1565
+ audio: [],
1566
+ video: []
1567
+ };
1568
+
1569
+ var micCount = 0;
1570
+ var outputCount = 0;
1571
+ var camCount = 0;
1572
+ for (var i = 0; i < devices.length; i++) {
1573
+ var device = devices[i];
1574
+ var ret = {
1575
+ id: device.deviceId,
1576
+ label: device.label
1577
+ };
1578
+ if (device.kind.indexOf("audio" + kind) === 0 && device.deviceId !== "communications") {
1579
+ ret.type = (device.kind === "audioinput") ? "mic" : "speaker";
1580
+ if (ret.type === "mic" && ret.label === "") {
1581
+ ret.label = 'microphone' + ++micCount;
1582
+ }
1583
+ if (ret.type === "speaker" && ret.label === "") {
1584
+ ret.label = 'speaker' + ++outputCount;
1585
+ }
1586
+ list.audio.push(ret);
1587
+ } else if (device.kind.indexOf("video" + kind) === 0) {
1588
+ if (!videoFilter || videoFilter.find((id) => id === device.deviceId)) {
1589
+ if (ret.label === "") {
1590
+ ret.label = 'camera' + ++camCount;
1591
+ }
1592
+ ret.type = "camera";
1593
+ list.video.push(ret);
1594
+ } else {
1595
+ logger.debug(LOG_PREFIX, "Video device " + device.deviceId + "does not conform the filter " + JSON.stringify(videoFilter));
1596
+ }
1597
+ } else {
1598
+ logger.debug(LOG_PREFIX, "unknown device " + device.kind + " id " + device.deviceId);
1599
+ }
1600
+ }
1601
+ return list;
1602
+ }
1603
+
1604
+ /**
1605
+ * Get media devices list
1606
+ *
1607
+ * @param labels
1608
+ * @param kind
1609
+ * @param deviceConstraints
1610
+ * @returns {Promise<{audio: [], video: []}>}
1611
+ */
1555
1612
  var listDevices = function (labels, kind, deviceConstraints) {
1556
1613
  //WCS-1963. added deviceConstraints.
1557
1614
  if (!deviceConstraints) {
@@ -1562,7 +1619,7 @@ var listDevices = function (labels, kind, deviceConstraints) {
1562
1619
  }
1563
1620
  if (!kind) {
1564
1621
  kind = constants.MEDIA_DEVICE_KIND.INPUT;
1565
- } else if (kind == "all") {
1622
+ } else if (kind === constants.MEDIA_DEVICE_KIND.ALL) {
1566
1623
  kind = "";
1567
1624
  }
1568
1625
  var getConstraints = function (devices) {
@@ -1570,9 +1627,9 @@ var listDevices = function (labels, kind, deviceConstraints) {
1570
1627
  for (var i = 0; i < devices.length; i++) {
1571
1628
  var device = devices[i];
1572
1629
  if (device.kind.indexOf("audio" + kind) === 0 && deviceConstraints.audio) {
1573
- constraints.audio = true;
1630
+ constraints.audio = deviceConstraints.audio;
1574
1631
  } else if (device.kind.indexOf("video" + kind) === 0 && deviceConstraints.video) {
1575
- constraints.video = true;
1632
+ constraints.video = deviceConstraints.video;
1576
1633
  } else {
1577
1634
  logger.debug(LOG_PREFIX, "unknown device " + device.kind + " id " + device.deviceId);
1578
1635
  }
@@ -1580,43 +1637,6 @@ var listDevices = function (labels, kind, deviceConstraints) {
1580
1637
  return constraints;
1581
1638
  };
1582
1639
 
1583
- var getList = function (devices) {
1584
- var list = {
1585
- audio: [],
1586
- video: []
1587
- };
1588
-
1589
- var micCount = 0;
1590
- var outputCount = 0;
1591
- var camCount = 0;
1592
- for (var i = 0; i < devices.length; i++) {
1593
- var device = devices[i];
1594
- var ret = {
1595
- id: device.deviceId,
1596
- label: device.label
1597
- };
1598
- if (device.kind.indexOf("audio" + kind) === 0 && device.deviceId != "communications") {
1599
- ret.type = (device.kind == "audioinput") ? "mic" : "speaker";
1600
- if (ret.type == "mic" && ret.label == "") {
1601
- ret.label = 'microphone' + ++micCount;
1602
- }
1603
- if (ret.type == "speaker" && ret.label == "") {
1604
- ret.label = 'speaker' + ++outputCount;
1605
- }
1606
- list.audio.push(ret);
1607
- } else if (device.kind.indexOf("video" + kind) === 0) {
1608
- if (ret.label == "") {
1609
- ret.label = 'camera' + ++camCount;
1610
- }
1611
- ret.type = "camera";
1612
- list.video.push(ret);
1613
- } else {
1614
- logger.debug(LOG_PREFIX, "unknown device " + device.kind + " id " + device.deviceId);
1615
- }
1616
- }
1617
- return list;
1618
- };
1619
-
1620
1640
  return new Promise(function (resolve, reject) {
1621
1641
  navigator.mediaDevices.enumerateDevices().then(function (devices) {
1622
1642
  if (labels) {
@@ -1628,19 +1648,96 @@ var listDevices = function (labels, kind, deviceConstraints) {
1628
1648
  }
1629
1649
  navigator.getUserMedia(constraints, function (stream) {
1630
1650
  navigator.mediaDevices.enumerateDevices().then(function (devicesWithLabels) {
1631
- resolve(getList(devicesWithLabels));
1651
+ resolve(getList(devicesWithLabels, kind));
1632
1652
  stream.getTracks().forEach(function (track) {
1633
1653
  track.stop();
1634
1654
  });
1635
1655
  }, reject);
1636
1656
  }, reject);
1637
1657
  } else {
1638
- resolve(getList(devices));
1658
+ resolve(getList(devices, kind));
1639
1659
  }
1640
1660
  }, reject);
1641
-
1642
1661
  });
1643
- };
1662
+ }
1663
+
1664
+ const getMobileDevices = async function (kind, deviceConstraints = null) {
1665
+ let constraints = {};
1666
+ let videoFilter = [];
1667
+ let list = null;
1668
+ if (!kind) {
1669
+ kind = constants.MEDIA_DEVICE_KIND.INPUT;
1670
+ } else if (kind === constants.MEDIA_DEVICE_KIND.ALL) {
1671
+ kind = "";
1672
+ }
1673
+ if (deviceConstraints && deviceConstraints.audio) {
1674
+ constraints.audio = deviceConstraints.audio;
1675
+ } else {
1676
+ constraints.audio = true;
1677
+ }
1678
+ if (deviceConstraints && deviceConstraints.video) {
1679
+ if (typeof deviceConstraints.video === 'object') {
1680
+ constraints.video = deviceConstraints.video;
1681
+ }
1682
+ else {
1683
+ constraints.video = {};
1684
+ }
1685
+ } else {
1686
+ constraints.video = {};
1687
+ }
1688
+
1689
+ const getCamera = async function (constraints, facingMode) {
1690
+ let deviceId = null;
1691
+ let mediaConstraints = {
1692
+ audio: false,
1693
+ video: constraints.video
1694
+ };
1695
+ mediaConstraints.video.facingMode = facingMode;
1696
+ try {
1697
+ stream = await navigator.mediaDevices.getUserMedia(mediaConstraints);
1698
+ if (stream) {
1699
+ if (stream.getVideoTracks().length > 0) {
1700
+ deviceId = stream.getVideoTracks()[0].getSettings().deviceId;
1701
+ }
1702
+ stream.getTracks().forEach((track) => {
1703
+ track.stop();
1704
+ });
1705
+ }
1706
+ } catch (error) {
1707
+ logger.error(LOG_PREFIX, "Can't get device access with video constraints " + JSON.stringify(constraints.video) + ", error " + error);
1708
+ }
1709
+ return deviceId;
1710
+ }
1711
+
1712
+ let front = await getCamera(constraints, { ideal: 'user' });
1713
+ if (front && front !== "") {
1714
+ logger.debug(LOG_PREFIX, "Front camera id: " + front);
1715
+ videoFilter.push(front);
1716
+ }
1717
+ let back = await getCamera(constraints, { ideal: 'environment' });
1718
+ if (back && back !== "") {
1719
+ logger.debug(LOG_PREFIX, "Back camera id: " + back);
1720
+ videoFilter.push(back);
1721
+ }
1722
+
1723
+ try {
1724
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
1725
+ if (stream) {
1726
+ const mediaDevices = await navigator.mediaDevices.enumerateDevices();
1727
+ if (mediaDevices) {
1728
+ logger.debug(LOG_PREFIX, "mediaDevices: " + JSON.stringify(mediaDevices));
1729
+ list = getList(mediaDevices, kind, videoFilter);
1730
+ }
1731
+ stream.getTracks().forEach(function (track) {
1732
+ track.stop();
1733
+ });
1734
+ }
1735
+ } catch (error) {
1736
+ logger.error(LOG_PREFIX, "Can't get device access with constraints " + JSON.stringify(constraints) + ", error " + error);
1737
+ }
1738
+
1739
+ return list;
1740
+ }
1644
1741
 
1645
1742
  function normalizeConstraints(constraints) {
1646
1743
  //WCS-2010. fixed TypeError after publish->stop->publish
@@ -1762,6 +1859,7 @@ module.exports = {
1762
1859
  getMediaAccess: getMediaAccess,
1763
1860
  releaseMedia: releaseMedia,
1764
1861
  listDevices: listDevices,
1862
+ getMobileDevices: getMobileDevices,
1765
1863
  playFirstSound: playFirstSound,
1766
1864
  playFirstVideo: playFirstVideo,
1767
1865
  available: available,