@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/docTemplate/README.md +1 -1
- package/examples/demo/streaming/media_devices_manager/manager.js +83 -80
- package/flashphoner-no-flash.js +286 -73
- package/flashphoner-no-flash.min.js +2 -2
- package/flashphoner-no-webrtc.js +85 -33
- package/flashphoner-no-webrtc.min.js +2 -2
- package/flashphoner-no-wsplayer.js +286 -73
- package/flashphoner-no-wsplayer.min.js +2 -2
- package/flashphoner-room-api-webrtc-only.js +286 -73
- package/flashphoner-room-api-webrtc-only.min.js +1 -1
- package/flashphoner-room-api.js +221 -72
- package/flashphoner-room-api.min.js +2 -2
- package/flashphoner-temasys-flash-websocket-without-adapterjs.js +85 -33
- package/flashphoner-temasys-flash-websocket.js +85 -33
- package/flashphoner-temasys-flash-websocket.min.js +1 -1
- package/flashphoner-webrtc-only.js +286 -73
- package/flashphoner-webrtc-only.min.js +1 -1
- package/flashphoner.js +286 -73
- package/flashphoner.min.js +2 -2
- package/package.json +1 -1
- package/src/flashphoner-core.js +67 -27
- package/src/stats-collector.js +12 -1
- package/src/webrtc-media-provider.js +142 -44
package/package.json
CHANGED
package/src/flashphoner-core.js
CHANGED
|
@@ -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
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
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,
|
package/src/stats-collector.js
CHANGED
|
@@ -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
|
|
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 =
|
|
1630
|
+
constraints.audio = deviceConstraints.audio;
|
|
1574
1631
|
} else if (device.kind.indexOf("video" + kind) === 0 && deviceConstraints.video) {
|
|
1575
|
-
constraints.video =
|
|
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,
|