@reactoo/watchtogether-sdk-js 2.7.7 → 2.7.9
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/dist/watchtogether-sdk.js +1785 -203
- package/dist/watchtogether-sdk.min.js +2 -2
- package/example/index.html +91 -35
- package/package.json +2 -2
- package/src/models/asset.js +24 -12
- package/src/models/room-session.js +7 -5
- package/src/models/user.js +21 -9
- package/src/modules/wt-room.js +170 -65
- package/src/modules/wt-utils.js +9 -1
package/src/modules/wt-room.js
CHANGED
|
@@ -181,17 +181,39 @@ class RoomSession {
|
|
|
181
181
|
this.userId = null;
|
|
182
182
|
this.sessiontype = type;
|
|
183
183
|
this.initialBitrate = 0;
|
|
184
|
-
this.simulcast = false;
|
|
185
184
|
this.enableDtx = false;
|
|
186
|
-
this.
|
|
187
|
-
this.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
185
|
+
this.simulcast = false;
|
|
186
|
+
this.defaultSimulcastSettings = {
|
|
187
|
+
"default" : {
|
|
188
|
+
mode: "controlled", // controlled, manual, browserController
|
|
189
|
+
defaultSubstream: 0, // 2 lowest quality, 0 highest quality
|
|
190
|
+
bitrates: [
|
|
191
|
+
{
|
|
192
|
+
"rid": "l",
|
|
193
|
+
"active": true,
|
|
194
|
+
"maxBitrate": 180000,
|
|
195
|
+
"maxFramerate": 20,
|
|
196
|
+
"scaleResolutionDownBy": 3.3333333333333335,
|
|
197
|
+
"priority": "low"
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
"rid": "m",
|
|
201
|
+
"active": true,
|
|
202
|
+
"maxBitrate": 500000,
|
|
203
|
+
"maxFramerate": 25,
|
|
204
|
+
"scaleResolutionDownBy": 1.3333333333333335,
|
|
205
|
+
"priority": "low"
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
"rid": "h",
|
|
209
|
+
"active": true,
|
|
210
|
+
"maxBitrate": 2000000,
|
|
211
|
+
"maxFramerate": 30,
|
|
212
|
+
"priority": "low"
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
};
|
|
195
217
|
this.recordingFilename = null;
|
|
196
218
|
this.pluginName = RoomSession.sessionTypes[type];
|
|
197
219
|
this.id = null;
|
|
@@ -217,6 +239,8 @@ class RoomSession {
|
|
|
217
239
|
this._statsTimeoutId = null;
|
|
218
240
|
this._statsInterval = 1000;
|
|
219
241
|
this._aqInterval = 2500;
|
|
242
|
+
this._aqIntervalCounter = 0;
|
|
243
|
+
this._aqIntervalDivisor = 4;
|
|
220
244
|
this._aqTimeoutId = null;
|
|
221
245
|
this._sendMessageTimeout = 5000;
|
|
222
246
|
this._retries = 0;
|
|
@@ -995,7 +1019,7 @@ class RoomSession {
|
|
|
995
1019
|
stats: {},
|
|
996
1020
|
selectedSubstream: {},
|
|
997
1021
|
initialSimulcastSubstreamBeenSet: {},
|
|
998
|
-
|
|
1022
|
+
overriddenSimulcastMode: {},
|
|
999
1023
|
};
|
|
1000
1024
|
|
|
1001
1025
|
if (handleId === this.handleId) {
|
|
@@ -1052,7 +1076,7 @@ class RoomSession {
|
|
|
1052
1076
|
stats: {},
|
|
1053
1077
|
selectedSubstream: {},
|
|
1054
1078
|
initialSimulcastSubstreamBeenSet: {},
|
|
1055
|
-
|
|
1079
|
+
overriddenSimulcastMode: {},
|
|
1056
1080
|
}
|
|
1057
1081
|
};
|
|
1058
1082
|
this._participants.push(handle);
|
|
@@ -1288,9 +1312,7 @@ class RoomSession {
|
|
|
1288
1312
|
initialBitrate = 0,
|
|
1289
1313
|
recordingFilename,
|
|
1290
1314
|
simulcast = false,
|
|
1291
|
-
|
|
1292
|
-
simulcastMode = this.simulcastMode,
|
|
1293
|
-
simulcastDefaultManualSubstream = this.simulcastDefaultManualSubstream,
|
|
1315
|
+
simulcastSettings = this.defaultSimulcastSettings,
|
|
1294
1316
|
enableDtx = false
|
|
1295
1317
|
) {
|
|
1296
1318
|
|
|
@@ -1318,16 +1340,20 @@ class RoomSession {
|
|
|
1318
1340
|
this.isConnecting = true;
|
|
1319
1341
|
this.enableDtx = enableDtx;
|
|
1320
1342
|
this.simulcast = simulcast;
|
|
1321
|
-
this.
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1343
|
+
this.simulcastSettings = structuredClone(simulcastSettings);
|
|
1344
|
+
|
|
1345
|
+
// sort simulcast bitrates
|
|
1346
|
+
if(this.simulcastSettings && typeof this.simulcastSettings === 'object' && Object.keys(this.simulcastSettings).length) {
|
|
1347
|
+
Object.keys(this.simulcastSettings).forEach(k => {
|
|
1348
|
+
this.simulcastSettings[k].bitrates = this.simulcastSettings[k].bitrates.sort((a, b) => {
|
|
1349
|
+
if(a.maxBitrate === b.maxBitrate) {
|
|
1350
|
+
return a.maxFramerate - b.maxFramerate;
|
|
1351
|
+
}
|
|
1352
|
+
return a.maxBitrate - b.maxBitrate;
|
|
1353
|
+
});
|
|
1329
1354
|
});
|
|
1330
1355
|
}
|
|
1356
|
+
|
|
1331
1357
|
this.emit('joining', true);
|
|
1332
1358
|
return new Promise((resolve, reject) => {
|
|
1333
1359
|
|
|
@@ -1551,6 +1577,17 @@ class RoomSession {
|
|
|
1551
1577
|
return this._participants.find(p => p.handleId === handleId || (rfid && p.rfid === rfid) || (userId && decodeJanusDisplay(p.userId)?.userId === userId));
|
|
1552
1578
|
}
|
|
1553
1579
|
|
|
1580
|
+
|
|
1581
|
+
_findSimulcastConfig(source, settings) {
|
|
1582
|
+
return Object.keys(settings).reduce((acc, key) => {
|
|
1583
|
+
if(settings[source]) {
|
|
1584
|
+
return settings[source];
|
|
1585
|
+
} else if(source.indexOf(key.match(/\*(.*?)\*/)?.[1]) > -1) {
|
|
1586
|
+
return settings[key];
|
|
1587
|
+
} else return acc;
|
|
1588
|
+
}, settings['default']);
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1554
1591
|
_disableStatsWatch() {
|
|
1555
1592
|
if (this._statsTimeoutId) {
|
|
1556
1593
|
clearInterval(this._statsTimeout);
|
|
@@ -1593,9 +1630,11 @@ class RoomSession {
|
|
|
1593
1630
|
if(this._aqTimeoutId) {
|
|
1594
1631
|
clearTimeout(this._aqTimeoutId);
|
|
1595
1632
|
this._aqTimeoutId = null;
|
|
1633
|
+
this._aqIntervalCounter = 0;
|
|
1596
1634
|
}
|
|
1597
|
-
|
|
1598
|
-
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
const checkStats = () => {
|
|
1599
1638
|
this._participants.forEach(p => {
|
|
1600
1639
|
if(p.handleId !== this.handleId) {
|
|
1601
1640
|
|
|
@@ -1605,27 +1644,21 @@ class RoomSession {
|
|
|
1605
1644
|
|
|
1606
1645
|
const {source, simulcastBitrates} = p.webrtcStuff.tracksMap.find(t => t.mid === mid) || {};
|
|
1607
1646
|
|
|
1647
|
+
// track is gone
|
|
1608
1648
|
if(!simulcastBitrates) {
|
|
1609
1649
|
return;
|
|
1610
1650
|
}
|
|
1611
1651
|
|
|
1652
|
+
const simulcastConfigForSource = this._findSimulcastConfig(source, this.simulcastSettings);
|
|
1612
1653
|
const initialSubstreamBeenSet = !!p.webrtcStuff.initialSimulcastSubstreamBeenSet[mid];
|
|
1654
|
+
const defaultSelectedSubstream = p.webrtcStuff?.overriddenSimulcastMode[mid]?.defaultSubstream || simulcastConfigForSource?.defaultSubstream;
|
|
1655
|
+
const simulcastMode = p.webrtcStuff?.overriddenSimulcastMode[mid]?.mode || simulcastConfigForSource?.mode;
|
|
1613
1656
|
|
|
1614
|
-
|
|
1615
|
-
? (this.simulcastDefaultManualSubstream[source] !== undefined
|
|
1616
|
-
? this.simulcastDefaultManualSubstream[source]
|
|
1617
|
-
: this.simulcastDefaultManualSubstream['default'])
|
|
1618
|
-
: this.simulcastDefaultManualSubstream;
|
|
1619
|
-
|
|
1620
|
-
const simulcastMode = typeof this.simulcastMode === 'object'
|
|
1621
|
-
? (this.simulcastMode[source] !== undefined ? this.simulcastMode[source] : this.simulcastMode['default'])
|
|
1622
|
-
: this.simulcastMode;
|
|
1623
|
-
|
|
1624
|
-
if((simulcastMode === 'browserControlled' || p.webrtcStuff.forcedBrowserControlledMode[mid])) {
|
|
1657
|
+
if((simulcastMode === 'browserControlled')) {
|
|
1625
1658
|
// do nothing
|
|
1626
1659
|
}
|
|
1627
|
-
|
|
1628
|
-
else if(simulcastMode === 'manual' || !initialSubstreamBeenSet) {
|
|
1660
|
+
|
|
1661
|
+
else if((simulcastMode === 'manual' && this._aqIntervalCounter % this._aqIntervalDivisor === 0) || !initialSubstreamBeenSet) {
|
|
1629
1662
|
p.webrtcStuff.initialSimulcastSubstreamBeenSet[mid] = true;
|
|
1630
1663
|
const currentSubstream = p.webrtcStuff.selectedSubstream[mid];
|
|
1631
1664
|
if(defaultSelectedSubstream !== undefined && defaultSelectedSubstream !== null && defaultSelectedSubstream !== currentSubstream) {
|
|
@@ -1638,17 +1671,18 @@ class RoomSession {
|
|
|
1638
1671
|
else if(simulcastMode === 'controlled') {
|
|
1639
1672
|
const currentSubstream = p.webrtcStuff.selectedSubstream[mid];
|
|
1640
1673
|
const settingsForCurrentSubstream = simulcastBitrates?.[simulcastBitrates.length - 1 - currentSubstream];
|
|
1674
|
+
|
|
1641
1675
|
let directionDecision = 0;
|
|
1642
1676
|
if(p.webrtcStuff?.stats?.[mid]?.length > this._upStatsLength) {
|
|
1643
1677
|
const upMedianStats = this._calculateMedianStats(p.webrtcStuff.stats[mid].slice(this._upStatsLength * -1));
|
|
1644
|
-
if(upMedianStats?.framesPerSecond >= Math.floor((settingsForCurrentSubstream?.maxFramerate || 30) * 0.7) && upMedianStats?.freezeDurationSinceLast < (this._upStatsLength * this._statsInterval * 0.33) / 1000 && upMedianStats?.freezeCountSinceLast < 3) {
|
|
1678
|
+
if(upMedianStats?.framesPerSecond >= Math.floor((settingsForCurrentSubstream?.maxFramerate || 30) * 0.7) && upMedianStats?.freezeDurationSinceLast < (this._upStatsLength * this._statsInterval * 0.33) / 1000 /* && upMedianStats?.freezeCountSinceLast < 3 */) {
|
|
1645
1679
|
directionDecision = 1;
|
|
1646
1680
|
}
|
|
1647
1681
|
}
|
|
1648
1682
|
|
|
1649
1683
|
if(p.webrtcStuff?.stats?.[mid]?.length > this._downStatsLength) {
|
|
1650
1684
|
const downMedianStats = this._calculateMedianStats(p.webrtcStuff.stats[mid].slice(this._downStatsLength * -1));
|
|
1651
|
-
if(downMedianStats?.framesPerSecond < Math.floor((settingsForCurrentSubstream?.maxFramerate || 30) * 0.7) || downMedianStats?.freezeDurationSinceLast > (this._downStatsLength * this._statsInterval * 0.33) / 1000 || downMedianStats?.freezeCountSinceLast > 5
|
|
1685
|
+
if(downMedianStats?.framesPerSecond < Math.floor((settingsForCurrentSubstream?.maxFramerate || 30) * 0.7) || downMedianStats?.freezeDurationSinceLast > (this._downStatsLength * this._statsInterval * 0.33) / 1000 /* || downMedianStats?.freezeCountSinceLast > 5 || downMedianStats?.jitter > maxJitter(settingsForCurrentSubstream.maxFramerate) */) {
|
|
1652
1686
|
directionDecision = -1;
|
|
1653
1687
|
}
|
|
1654
1688
|
}
|
|
@@ -1676,13 +1710,19 @@ class RoomSession {
|
|
|
1676
1710
|
});
|
|
1677
1711
|
}
|
|
1678
1712
|
})
|
|
1679
|
-
|
|
1713
|
+
|
|
1714
|
+
this._aqIntervalCounter++;
|
|
1715
|
+
this._aqTimeoutId = setTimeout(checkStats, this._aqInterval);
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
checkStats();
|
|
1680
1719
|
}
|
|
1681
1720
|
|
|
1682
1721
|
_disableSubstreamAutoSelect() {
|
|
1683
1722
|
if(this._aqTimeoutId) {
|
|
1684
1723
|
clearTimeout(this._aqTimeoutId);
|
|
1685
1724
|
this._aqTimeoutId = null;
|
|
1725
|
+
this._aqIntervalCounter = 0;
|
|
1686
1726
|
}
|
|
1687
1727
|
}
|
|
1688
1728
|
|
|
@@ -1737,6 +1777,10 @@ class RoomSession {
|
|
|
1737
1777
|
powerEfficientDecoder: null,
|
|
1738
1778
|
};
|
|
1739
1779
|
participantStats.stats.forEach(report => {
|
|
1780
|
+
|
|
1781
|
+
const simulcastConfigForSource = this._findSimulcastConfig(participantStats.source, this.simulcastSettings);
|
|
1782
|
+
const simulcastMode = handle.webrtcStuff?.overriddenSimulcastMode[participantStats.mid]?.mode || simulcastConfigForSource?.mode ;
|
|
1783
|
+
|
|
1740
1784
|
if(report.type === 'inbound-rtp' && report.kind === 'video') {
|
|
1741
1785
|
stats.framesPerSecond = report.framesPerSecond || 0;
|
|
1742
1786
|
stats.framesDropped = report.framesDropped || 0;
|
|
@@ -1759,14 +1803,7 @@ class RoomSession {
|
|
|
1759
1803
|
}
|
|
1760
1804
|
|
|
1761
1805
|
stats.selectedSubstream = handle.webrtcStuff.selectedSubstream[participantStats.mid];
|
|
1762
|
-
|
|
1763
|
-
stats.simulcastMode = 'browserControlled';
|
|
1764
|
-
}
|
|
1765
|
-
else {
|
|
1766
|
-
stats.simulcastMode = typeof this.simulcastMode === 'object'
|
|
1767
|
-
? (this.simulcastMode[participantStats.source] !== undefined ? this.simulcastMode[participantStats.source] : this.simulcastMode['default'])
|
|
1768
|
-
: this.simulcastMode;
|
|
1769
|
-
}
|
|
1806
|
+
stats.simulcastMode = simulcastMode;
|
|
1770
1807
|
|
|
1771
1808
|
});
|
|
1772
1809
|
|
|
@@ -2060,6 +2097,10 @@ class RoomSession {
|
|
|
2060
2097
|
});
|
|
2061
2098
|
};
|
|
2062
2099
|
|
|
2100
|
+
let mutedTimerId = {};
|
|
2101
|
+
let waitPeriod = 300; // ms
|
|
2102
|
+
let screenShareWaitPeriod = 5000; // ms
|
|
2103
|
+
|
|
2063
2104
|
event.track.onmute = (ev) => {
|
|
2064
2105
|
this._log('Remote track muted');
|
|
2065
2106
|
|
|
@@ -2081,22 +2122,35 @@ class RoomSession {
|
|
|
2081
2122
|
muted: true
|
|
2082
2123
|
});
|
|
2083
2124
|
|
|
2084
|
-
//
|
|
2085
|
-
// when a track is muted, we try to switch to lower quality substream
|
|
2125
|
+
// when a track is muted, we try to switch to lower quality substream, but not for screen sharing
|
|
2086
2126
|
|
|
2087
2127
|
if(!this.simulcast) {
|
|
2088
2128
|
return;
|
|
2089
2129
|
}
|
|
2090
2130
|
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
.
|
|
2131
|
+
const wPeriod = source.indexOf('screen') > -1 ? screenShareWaitPeriod : waitPeriod;
|
|
2132
|
+
|
|
2133
|
+
if(!mutedTimerId[mid]) {
|
|
2134
|
+
mutedTimerId[mid] = setTimeout(() => {
|
|
2135
|
+
mutedTimerId[mid] = null;
|
|
2136
|
+
const simulcastConfigForSource = this._findSimulcastConfig(source, this.simulcastSettings);
|
|
2137
|
+
const simulcastMode = handle.webrtcStuff?.overriddenSimulcastMode[mid]?.mode || simulcastConfigForSource?.mode;
|
|
2138
|
+
const {simulcastBitrates} = handle.webrtcStuff.tracksMap.find(t => t.mid === mid) || {};
|
|
2139
|
+
|
|
2140
|
+
// track is gone
|
|
2141
|
+
if(!simulcastBitrates) {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
const currentSubstream = handle.webrtcStuff.selectedSubstream[mid];
|
|
2146
|
+
if(!(simulcastMode === 'browserControlled') && ev.target.kind === 'video' && currentSubstream < simulcastBitrates.length - 1) {
|
|
2147
|
+
this._log('Attempting to down the quality due to track muted');
|
|
2148
|
+
this.selectSubStream(handle.handleId, currentSubstream + 1, undefined, mid, false)
|
|
2149
|
+
.catch((reason) => this._log(`Changing substream for mid: ${mid} failed. Reason: ${reason}`));
|
|
2150
|
+
}
|
|
2151
|
+
}, wPeriod);
|
|
2099
2152
|
}
|
|
2153
|
+
|
|
2100
2154
|
};
|
|
2101
2155
|
|
|
2102
2156
|
event.track.onunmute = (ev) => {
|
|
@@ -2106,6 +2160,12 @@ class RoomSession {
|
|
|
2106
2160
|
t => t.receiver.track === ev.target);
|
|
2107
2161
|
let mid = transceiver.mid || ev.target.id;
|
|
2108
2162
|
let source = Object.keys(config.streamMap).find(key => config.streamMap[key].includes(ev.target.id));
|
|
2163
|
+
|
|
2164
|
+
if(mutedTimerId[mid]) {
|
|
2165
|
+
clearTimeout(mutedTimerId[mid]);
|
|
2166
|
+
mutedTimerId[mid] = null;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2109
2169
|
this.emit('remoteTrackMuted', {
|
|
2110
2170
|
id: handle.handleId,
|
|
2111
2171
|
mid,
|
|
@@ -2591,6 +2651,7 @@ class RoomSession {
|
|
|
2591
2651
|
config.stream.removeTrack(oldVideoStream);
|
|
2592
2652
|
}
|
|
2593
2653
|
|
|
2654
|
+
const simulcastConfigForSource = this._findSimulcastConfig(source, this.simulcastSettings);
|
|
2594
2655
|
let audioTrackReplacePromise = Promise.resolve();
|
|
2595
2656
|
let videoTrackReplacePromise = Promise.resolve();
|
|
2596
2657
|
|
|
@@ -2646,11 +2707,12 @@ class RoomSession {
|
|
|
2646
2707
|
}
|
|
2647
2708
|
else {
|
|
2648
2709
|
if(adapter.browserDetails.browser !== 'firefox') {
|
|
2710
|
+
|
|
2649
2711
|
// standard
|
|
2650
2712
|
config.pc.addTransceiver(stream.getVideoTracks()[0], {
|
|
2651
2713
|
direction: 'sendonly',
|
|
2652
2714
|
streams: [config.stream],
|
|
2653
|
-
sendEncodings: structuredClone(
|
|
2715
|
+
sendEncodings: structuredClone(simulcastConfigForSource?.bitrates)
|
|
2654
2716
|
})
|
|
2655
2717
|
}
|
|
2656
2718
|
else {
|
|
@@ -2662,7 +2724,7 @@ class RoomSession {
|
|
|
2662
2724
|
let sender = transceiver ? transceiver.sender : null;
|
|
2663
2725
|
if(sender) {
|
|
2664
2726
|
let parameters = sender.getParameters() || {};
|
|
2665
|
-
parameters.encodings = stream.getVideoTracks()[0].sendEncodings || structuredClone(
|
|
2727
|
+
parameters.encodings = stream.getVideoTracks()[0].sendEncodings || structuredClone(simulcastConfigForSource?.bitrates);
|
|
2666
2728
|
sender.setParameters(parameters);
|
|
2667
2729
|
}
|
|
2668
2730
|
}
|
|
@@ -2796,10 +2858,11 @@ class RoomSession {
|
|
|
2796
2858
|
|
|
2797
2859
|
let descriptions = [];
|
|
2798
2860
|
Object.keys(config.streamMap).forEach(source => {
|
|
2861
|
+
const simulcastConfigForSource = this._findSimulcastConfig(source, this.simulcastSettings);
|
|
2799
2862
|
config.streamMap[source].forEach(trackId => {
|
|
2800
2863
|
let t = transceivers.find(transceiver => transceiver.sender.track && transceiver.sender.track.id === trackId)
|
|
2801
2864
|
if(t) {
|
|
2802
|
-
descriptions.push({mid: t.mid, description: JSON.stringify({source, simulcastBitrates:
|
|
2865
|
+
descriptions.push({mid: t.mid, description: JSON.stringify({source, simulcastBitrates: simulcastConfigForSource?.bitrates, intercomGroups: this._talkIntercomChannels})});
|
|
2803
2866
|
}
|
|
2804
2867
|
})
|
|
2805
2868
|
});
|
|
@@ -2993,6 +3056,39 @@ class RoomSession {
|
|
|
2993
3056
|
}
|
|
2994
3057
|
}
|
|
2995
3058
|
|
|
3059
|
+
overrideSimulcastSettings(handleId, mid, source, settings = {}) {
|
|
3060
|
+
const {mode, defaultSubstream} = settings;
|
|
3061
|
+
let handle = this._getHandle(handleId);
|
|
3062
|
+
if(!handle) {
|
|
3063
|
+
return Promise.resolve();
|
|
3064
|
+
}
|
|
3065
|
+
let config = handle.webrtcStuff;
|
|
3066
|
+
if(source !== undefined || mid !== undefined) {
|
|
3067
|
+
if(mid === undefined) {
|
|
3068
|
+
let transceivers = config.pc.getTransceivers();
|
|
3069
|
+
for(let trackId of config.streamMap[source]) {
|
|
3070
|
+
let transceiver = transceivers.find(transceiver => transceiver.receiver.track && transceiver.receiver.track.kind === 'video' && transceiver.receiver.track.id === trackId)
|
|
3071
|
+
if(transceiver) {
|
|
3072
|
+
mid = transceiver.mid;
|
|
3073
|
+
break;
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
if(mid !== undefined) {
|
|
3079
|
+
if(!config.overriddenSimulcastMode[mid]) {
|
|
3080
|
+
config.overriddenSimulcastMode[mid] = {};
|
|
3081
|
+
}
|
|
3082
|
+
config.overriddenSimulcastMode[mid]['defaultSubstream'] = defaultSubstream;
|
|
3083
|
+
config.overriddenSimulcastMode[mid]['mode'] = mode;
|
|
3084
|
+
return true;
|
|
3085
|
+
}
|
|
3086
|
+
else {
|
|
3087
|
+
return false;
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
|
|
2996
3092
|
selectSubStream(handleId, substream = 2, source, mid, manual = false) {
|
|
2997
3093
|
this._log('Select substream called for handle:', handleId, 'Source or mid:', source ? source : mid, 'Substream:', substream);
|
|
2998
3094
|
let handle = this._getHandle(handleId);
|
|
@@ -3036,10 +3132,17 @@ class RoomSession {
|
|
|
3036
3132
|
}
|
|
3037
3133
|
}
|
|
3038
3134
|
if(mid !== undefined) {
|
|
3135
|
+
|
|
3136
|
+
if(!config.overriddenSimulcastMode[mid]) {
|
|
3137
|
+
config.overriddenSimulcastMode[mid] = {};
|
|
3138
|
+
}
|
|
3139
|
+
|
|
3039
3140
|
if(substream === null) {
|
|
3040
3141
|
|
|
3041
3142
|
if(manual) {
|
|
3042
|
-
|
|
3143
|
+
// reset to previous state
|
|
3144
|
+
config.overriddenSimulcastMode[mid]['defaultSubstream'] = null;
|
|
3145
|
+
config.overriddenSimulcastMode[mid]['mode'] = null;
|
|
3043
3146
|
}
|
|
3044
3147
|
|
|
3045
3148
|
resolve({substream, sender: handleId});
|
|
@@ -3047,7 +3150,8 @@ class RoomSession {
|
|
|
3047
3150
|
}
|
|
3048
3151
|
|
|
3049
3152
|
if(manual) {
|
|
3050
|
-
config.
|
|
3153
|
+
config.overriddenSimulcastMode[mid]['defaultSubstream'] = substream;
|
|
3154
|
+
config.overriddenSimulcastMode[mid]['mode'] = "manual";
|
|
3051
3155
|
}
|
|
3052
3156
|
|
|
3053
3157
|
this.ws.addEventListener('message', parseResponse);
|
|
@@ -3094,10 +3198,11 @@ class RoomSession {
|
|
|
3094
3198
|
let transceivers = config.pc.getTransceivers();
|
|
3095
3199
|
let descriptions = [];
|
|
3096
3200
|
Object.keys(config.streamMap).forEach(source => {
|
|
3201
|
+
const simulcastConfigForSource = this._findSimulcastConfig(source, this.simulcastSettings);
|
|
3097
3202
|
config.streamMap[source].forEach(trackId => {
|
|
3098
3203
|
let t = transceivers.find(transceiver => transceiver.sender.track && transceiver.sender.track.id === trackId)
|
|
3099
3204
|
if(t) {
|
|
3100
|
-
descriptions.push({mid: t.mid, description: JSON.stringify({simulcastBitrates:
|
|
3205
|
+
descriptions.push({mid: t.mid, description: JSON.stringify({simulcastBitrates: simulcastConfigForSource?.bitrates, intercomGroups: groups, source:source})});
|
|
3101
3206
|
}
|
|
3102
3207
|
})
|
|
3103
3208
|
});
|
package/src/modules/wt-utils.js
CHANGED
|
@@ -128,6 +128,14 @@ const maxJitter = (x) => {
|
|
|
128
128
|
return a / (1 + Math.exp(-b * (x - c))) + d; // Fixed the typo here
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
const chunkArray = (array, chunkSize) => {
|
|
132
|
+
if (!array?.length) return [[]];
|
|
131
133
|
|
|
134
|
+
let results = [];
|
|
135
|
+
while (array.length) {
|
|
136
|
+
results.push(array.splice(0, chunkSize));
|
|
137
|
+
}
|
|
138
|
+
return results;
|
|
139
|
+
}
|
|
132
140
|
|
|
133
|
-
export {wait, getBrowserFingerprint, generateUUID, decodeJanusDisplay, setExactTimeout, clearExactTimeout, median, maxJitter}
|
|
141
|
+
export {wait, getBrowserFingerprint, generateUUID, decodeJanusDisplay, setExactTimeout, clearExactTimeout, median, maxJitter, chunkArray}
|