@reactoo/watchtogether-sdk-js 2.7.88 → 2.7.90

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": "@reactoo/watchtogether-sdk-js",
3
- "version": "2.7.88",
3
+ "version": "2.7.90",
4
4
  "description": "Javascript SDK for Reactoo",
5
5
  "main": "dist/watchtogether-sdk.min.js",
6
6
  "module": "dist/watchtogether-sdk.min.js",
package/src/models/iot.js CHANGED
@@ -255,6 +255,10 @@ let iot = function () {
255
255
  return this.iot.__promise.then(() => this.__privates.iot.send(topic,message));
256
256
  },
257
257
 
258
+ emitMessage: (message) => {
259
+ this.__privates.iot.emitMessage(message);
260
+ },
261
+
258
262
  $once: (key, callback, that) => {
259
263
  return this.__privates.iot.once(key, callback, that || this);
260
264
  },
@@ -115,6 +115,7 @@ let roomSession = function ({roomId, pinHash, role, options = {}}, room, wt) {
115
115
  roomData.data.roomId,
116
116
  roomData.data.pin,
117
117
  roomData.data.href,
118
+ roomData.data.protocol,
118
119
  roomData.data.iceServers,
119
120
  roomData.data.accessToken,
120
121
  roomData.data.display,
@@ -251,6 +251,7 @@ class RoomSession {
251
251
  this.privateId = null;
252
252
  this.constructId = constructId || RoomSession.randomString(16);
253
253
  this.sessionId = null;
254
+ this.apisecret = null;
254
255
  this.handleId = null;
255
256
  this.ws = null;
256
257
  this.isRestarting = false;
@@ -276,6 +277,9 @@ class RoomSession {
276
277
  this._sendMessageTimeout = 10000;
277
278
  this._retries = 0;
278
279
  this._maxRetries = 5;
280
+ this._keepAlivePeriod = 25000;
281
+ this._longPollTimeout = 60000;
282
+ this._maxev = 10;
279
283
  this._keepAliveId = null;
280
284
  this._participants = [];
281
285
  this._restrictSubscribeToUserIds = []; // all if empty
@@ -297,6 +301,86 @@ class RoomSession {
297
301
  }
298
302
  }
299
303
 
304
+ _httpAPICall = function(url, options) {
305
+ return new Promise((resolve, reject) => {
306
+ const xhr = new XMLHttpRequest();
307
+
308
+ xhr.open(options.verb || 'POST', url);
309
+
310
+ // Set default headers
311
+ xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
312
+ if (options.verb === "POST") {
313
+ xhr.setRequestHeader('Content-Type', 'application/json');
314
+ }
315
+
316
+ // Handle credentials
317
+ if (options.withCredentials) {
318
+ xhr.withCredentials = true;
319
+ }
320
+
321
+ // Set timeout if specified
322
+ if (options.timeout) {
323
+ xhr.timeout = options.timeout;
324
+ }
325
+
326
+ // Setup handlers
327
+ xhr.onload = function() {
328
+ if (xhr.status >= 200 && xhr.status < 300) {
329
+ let response;
330
+ try {
331
+ response = JSON.parse(xhr.responseText);
332
+ } catch(e) {
333
+ if (options.error) {
334
+ options.error('Invalid JSON', xhr.responseText);
335
+ }
336
+ reject('Invalid JSON');
337
+ return;
338
+ }
339
+ if (options.success) {
340
+ options.success(response);
341
+ }
342
+ resolve(response);
343
+ } else {
344
+ let errorText = xhr.statusText || 'HTTP Error';
345
+ if (options.error) {
346
+ options.error(errorText, xhr.responseText);
347
+ }
348
+ reject(errorText);
349
+ }
350
+ };
351
+
352
+ xhr.onerror = function() {
353
+ let errorText = 'Network error';
354
+ if (options.error) {
355
+ options.error(errorText, 'Is the server down?');
356
+ }
357
+ reject(errorText);
358
+ };
359
+
360
+ xhr.ontimeout = function() {
361
+ let errorText = 'Request timed out';
362
+ if (options.error) {
363
+ options.error(errorText, 'Is the server down?');
364
+ }
365
+ reject(errorText);
366
+ };
367
+
368
+ // Send request
369
+ try {
370
+ if (options.body) {
371
+ xhr.send(JSON.stringify(options.body));
372
+ } else {
373
+ xhr.send();
374
+ }
375
+ } catch(e) {
376
+ if (options.error) {
377
+ options.error('Error sending request', e);
378
+ }
379
+ reject(e);
380
+ }
381
+ });
382
+ }
383
+
300
384
  _pushToRemoteUsersCache(userId, streams, id) {
301
385
  const existingIndex = this._remoteUsersCache.findIndex(u => u.userId === userId);
302
386
  if (existingIndex > -1) {
@@ -431,13 +515,34 @@ class RoomSession {
431
515
  })
432
516
  }
433
517
 
434
- _send(request = {}, ignoreResponse = false, dontResolveOnAck = false, retry = 0) {
435
-
518
+ _sendHTTP(request = {}, ignoreResponse = false, dontResolveOnAck = false, retry = 0) {
519
+ let transaction = RoomSession.randomString(12);
520
+ let requestData = {
521
+ ...request,
522
+ transaction,
523
+ token: this.token,
524
+ ...((this.sessionId && {'session_id': this.sessionId}) || {}),
525
+ ...((this.apisecret && {'apisecret': this.apisecret}) || {})
526
+ };
527
+ this._log(requestData);
528
+ return this._httpAPICall(this.server, {body:requestData})
529
+ .then(json => {
530
+ if(json['janus'] !== 'success' && json['janus'] !== 'ack') {
531
+ // TODO: check if this can stay like this
532
+ // not a success not an ack ... should be error
533
+ return Promise.reject(json["error"])
534
+ }
535
+ return json;
536
+ })
537
+ }
538
+ _sendWebsockets(request = {}, ignoreResponse = false, dontResolveOnAck = false, retry = 0) {
436
539
  let transaction = RoomSession.randomString(12);
437
540
  let requestData = {
438
541
  ...request,
439
542
  transaction,
440
- token: this.token, ...((this.sessionId && {'session_id': this.sessionId}) || {})
543
+ token: this.token,
544
+ ...((this.sessionId && {'session_id': this.sessionId}) || {}),
545
+ ...((this.apisecret && {'apisecret': this.apisecret}) || {})
441
546
  };
442
547
  this._log(requestData);
443
548
  const op = () => new Promise((resolve, reject) => {
@@ -503,6 +608,44 @@ class RoomSession {
503
608
  }
504
609
  })
505
610
  }
611
+ _send(request = {}, ignoreResponse = false, dontResolveOnAck = false, retry = 0) {
612
+ if(this.useWebsockets) {
613
+ return this._sendWebsockets(request, ignoreResponse, dontResolveOnAck, retry);
614
+ }
615
+ else {
616
+ return this._sendHTTP(request, ignoreResponse, dontResolveOnAck, retry)
617
+ }
618
+ }
619
+
620
+ _longPoll() {
621
+ let longpoll = this.server + "/" + this.sessionId + "?rid=" + new Date().getTime();
622
+ if(this._maxev)
623
+ longpoll = longpoll + "&maxev=" + this._maxev;
624
+ if(this.token)
625
+ longpoll = longpoll + "&token=" + encodeURIComponent(this.token);
626
+ if(this.apisecret)
627
+ longpoll = longpoll + "&apisecret=" + encodeURIComponent(this.apisecret);
628
+
629
+ this._httpAPICall(longpoll, {
630
+ verb: 'GET',
631
+ timeout: this._longPollTimeout
632
+ })
633
+ .then(this._handleWsEvents.bind(this))
634
+ .catch(() => {
635
+
636
+ this._retries++;
637
+ if(this._retries > this._maxRetries) {
638
+ if (this.sessiontype === 'reactooroom') {
639
+ this.disconnect(true);
640
+ } else if (this.sessiontype === 'streaming') {
641
+ this.stopStream();
642
+ }
643
+ this.emit('error', {type: 'error', id: 33, message: 'Lost connection to server', data: null});
644
+ }
645
+
646
+ this._longPoll();
647
+ })
648
+ }
506
649
 
507
650
  _connectionClosed() {
508
651
 
@@ -555,16 +698,36 @@ class RoomSession {
555
698
 
556
699
  this._keepAliveId = setTimeout(() => {
557
700
  this._startKeepAlive();
558
- }, 10000);
701
+ }, this._keepAlivePeriod);
559
702
  }
560
703
 
561
704
  _stopKeepAlive() {
562
705
  clearTimeout(this._keepAliveId);
563
706
  }
564
707
 
565
- _handleWsEvents(event) {
708
+ _handleWsEvents(event, skipPoll = false) {
709
+
710
+ this._retries = 0;
711
+
712
+ // we have a response from long poll, that means we need to run it again
713
+ if(!this.useWebsockets && !skipPoll) {
714
+ this._longPoll();
715
+ }
716
+
717
+ if(!this.useWebsockets && skipPoll) {
718
+ // we need to fire those events into the wild
719
+ this.emit('longPollEvent', event);
720
+ }
721
+
722
+ if(Array.isArray(event)) {
723
+ event.forEach(ev => this._handleWsEvents({data:ev}, true));
724
+ return;
725
+ }
726
+
727
+ let json = typeof event.data === 'string'
728
+ ? JSON.parse(event.data)
729
+ : event.data;
566
730
 
567
- let json = JSON.parse(event.data);
568
731
  var sender = json["sender"];
569
732
  var type = json["janus"];
570
733
 
@@ -1274,14 +1437,15 @@ class RoomSession {
1274
1437
  : Promise.resolve();
1275
1438
  }
1276
1439
 
1277
- // internal reconnect
1440
+ _webSocketConnection(reclaim = false) {
1278
1441
 
1279
- _reconnect() {
1280
-
1281
- if (this.isReclaiming) {
1282
- return Promise.resolve();
1442
+ if (this.isConnecting) {
1443
+ return Promise.reject({type: 'warning', id: 16, message: 'connection establishment already in progress'});
1283
1444
  }
1284
1445
 
1446
+ this.isConnecting = true;
1447
+ this.emit('joining', true);
1448
+
1285
1449
  if (this.ws) {
1286
1450
  this._wipeListeners();
1287
1451
  if (this.ws.readyState === 1) {
@@ -1289,60 +1453,153 @@ class RoomSession {
1289
1453
  }
1290
1454
  }
1291
1455
  this._stopKeepAlive();
1292
- this.isReclaiming = true;
1293
- this.emit('joining', true);
1456
+
1294
1457
  return new Promise((resolve, reject) => {
1295
1458
 
1296
- let abortReconnect = () => {
1297
- this._abortController.signal.removeEventListener('abort', abortReconnect);
1459
+ this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
1460
+ this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
1461
+
1462
+ let abortConnect = () => {
1463
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1298
1464
  this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
1299
1465
  this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
1300
1466
  this.ws.onopen = null;
1301
1467
  this.ws.onerror = null;
1302
- this.isReclaiming = false;
1468
+ this.isConnecting = false;
1303
1469
  this.emit('joining', false);
1304
- reject({type: 'warning', id: 17, message: 'Connection cancelled', data: e});
1470
+ reject({type: 'warning', id: 17, message: 'Connection cancelled'});
1305
1471
  };
1306
1472
 
1307
1473
  this.ws = new WebSocket(this.server, 'janus-protocol');
1308
- this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
1309
- this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
1310
1474
  this.ws.addEventListener('close', this.__connectionClosedBoundFn);
1311
1475
  this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
1476
+
1312
1477
  this.ws.onopen = () => {
1313
- this._abortController.signal.removeEventListener('abort', abortReconnect);
1314
- this._send({"janus": "claim"})
1315
- .then(json => {
1316
- this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1317
- this._startKeepAlive();
1318
- this.isReclaiming = false;
1319
- this.emit('joining', false);
1320
- this._retries = 0;
1321
- resolve(json);
1322
- })
1323
- .catch(error => {
1324
- this.isReclaiming = false;
1325
- this.emit('joining', false);
1326
- reject({type: 'error', id: 11, message: 'reconnection error', data: error})
1327
- });
1478
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1479
+
1480
+ if(!reclaim) {
1481
+
1482
+ this._send({"janus": "create"})
1483
+ .then(json => {
1484
+ this._retries = 0;
1485
+ this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1486
+ this._startKeepAlive();
1487
+ return 1;
1488
+ })
1489
+ .then(() => this._createParticipant(this.userId))
1490
+ .then(handle => {
1491
+ this.handleId = handle.handleId;
1492
+ return 1
1493
+ })
1494
+ .then(() => this._joinRoom(this.roomId, this.pin, this.userId, this.display))
1495
+ .then(() => {
1496
+ this._enableStatsWatch();
1497
+ this._enableSubstreamAutoSelect();
1498
+ this.isConnecting = false;
1499
+ this.emit('joining', false);
1500
+ resolve(this);
1501
+ })
1502
+ .catch(error => {
1503
+ this.isConnecting = false;
1504
+ this.emit('joining', false);
1505
+ reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
1506
+ });
1507
+
1508
+ }
1509
+
1510
+ else {
1511
+ this._send({"janus": "claim"})
1512
+ .then(json => {
1513
+ this._retries = 0;
1514
+ this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1515
+ this._startKeepAlive();
1516
+ this.isConnecting = false;
1517
+ this.emit('joining', false);
1518
+ resolve(json);
1519
+ })
1520
+ .catch(error => {
1521
+ this.isConnecting = false;
1522
+ this.emit('joining', false);
1523
+ reject({type: 'error', id: 11, message: 'reconnection error', data: error})
1524
+ });
1525
+ }
1526
+
1328
1527
  };
1329
1528
 
1330
- // this is called before 'close' event callback so it doesn't break reconnect loop
1331
1529
  this.ws.onerror = (e) => {
1332
- this._abortController.signal.removeEventListener('abort', abortReconnect);
1333
- this.isReclaiming = false;
1530
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1531
+ this.isConnecting = false;
1334
1532
  this.emit('joining', false);
1335
- reject({type: 'warning', id: 12, message: 'ws reconnection error', data: e});
1533
+ reject({type: 'error', id: 14, message: 'ws connection error', data: e});
1336
1534
  }
1337
1535
 
1338
- this._abortController.signal.addEventListener('abort', abortReconnect);
1536
+ this._abortController.signal.addEventListener('abort', abortConnect);
1537
+
1339
1538
  });
1340
1539
  }
1341
1540
 
1541
+ _httpConnection(reclaim = false) {
1542
+ if(!reclaim) {
1543
+ return this._send({"janus": "create"})
1544
+ .then(json => {
1545
+ this._retries = 0;
1546
+ this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1547
+ this._startKeepAlive();
1548
+ return 1;
1549
+ })
1550
+ .then(() => this._createParticipant(this.userId))
1551
+ .then(handle => {
1552
+ this.handleId = handle.handleId;
1553
+ return 1
1554
+ })
1555
+ .then(() => this._joinRoom(this.roomId, this.pin, this.userId, this.display))
1556
+ .then(() => {
1557
+ this._enableStatsWatch();
1558
+ this._enableSubstreamAutoSelect();
1559
+ this._longPoll();
1560
+ this.isConnecting = false;
1561
+ this.emit('joining', false);
1562
+ return Promise.resolve(this);
1563
+ })
1564
+ .catch(error => {
1565
+ this.isConnecting = false;
1566
+ this.emit('joining', false);
1567
+ return Promise.reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
1568
+ });
1569
+ }
1570
+ else {
1571
+ return this._send({"janus": "claim"})
1572
+ .then(json => {
1573
+ this._retries = 0;
1574
+ this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1575
+ this._startKeepAlive();
1576
+ this.isConnecting = false;
1577
+ this.emit('joining', false);
1578
+ return Promise.resolve(json);
1579
+ })
1580
+ .catch(error => {
1581
+ this.isConnecting = false;
1582
+ this.emit('joining', false);
1583
+ return Promise.reject({type: 'error', id: 11, message: 'reconnection error', data: error})
1584
+ });
1585
+ }
1586
+ }
1587
+
1588
+
1589
+ // internal reconnect
1590
+ _reconnect() {
1591
+ if(this.useWebsockets) {
1592
+ return this._webSocketConnection(true)
1593
+ }
1594
+ else {
1595
+ return this._httpConnection(true)
1596
+ }
1597
+ }
1342
1598
  connect(
1343
1599
  roomId,
1344
1600
  pin,
1345
1601
  server,
1602
+ protocol,
1346
1603
  iceServers,
1347
1604
  token,
1348
1605
  display,
@@ -1359,14 +1616,11 @@ class RoomSession {
1359
1616
  return Promise.reject({type: 'warning', id: 16, message: 'connection already in progress'});
1360
1617
  }
1361
1618
 
1362
- if (this.ws) {
1363
- this._wipeListeners();
1364
- }
1365
- this._stopKeepAlive();
1366
1619
  this._abortController = new AbortController();
1367
1620
 
1368
1621
  this.sessionId = null;
1369
1622
  this.server = server;
1623
+ this.protocol = protocol;
1370
1624
  this.iceServers = iceServers;
1371
1625
  this.token = token;
1372
1626
  this.roomId = roomId;
@@ -1376,10 +1630,10 @@ class RoomSession {
1376
1630
  this.webrtcVersion = webrtcVersion;
1377
1631
  this.initialBitrate = initialBitrate;
1378
1632
  this.recordingFilename = recordingFilename;
1379
- this.isConnecting = true;
1380
1633
  this.enableDtx = enableDtx;
1381
1634
  this.simulcast = simulcast;
1382
1635
  this.simulcastSettings = structuredClone(simulcastSettings);
1636
+ this.useWebsockets = this.protocol === 'ws' || this.protocol === 'wss';
1383
1637
 
1384
1638
  // sort simulcast bitrates
1385
1639
  if(this.simulcastSettings && typeof this.simulcastSettings === 'object' && Object.keys(this.simulcastSettings).length) {
@@ -1393,65 +1647,12 @@ class RoomSession {
1393
1647
  });
1394
1648
  }
1395
1649
 
1396
- this.emit('joining', true);
1397
- return new Promise((resolve, reject) => {
1398
-
1399
- this.ws = new WebSocket(this.server, 'janus-protocol');
1400
- this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
1401
- this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
1402
-
1403
- let abortConnect = () => {
1404
- this._abortController.signal.removeEventListener('abort', abortConnect);
1405
- this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
1406
- this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
1407
- this.ws.onopen = null;
1408
- this.ws.onerror = null;
1409
- this.isConnecting = false;
1410
- this.emit('joining', false);
1411
- reject({type: 'warning', id: 17, message: 'Connection cancelled'});
1412
- };
1413
-
1414
- this.ws.addEventListener('close', this.__connectionClosedBoundFn);
1415
- this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
1416
- this.ws.onopen = () => {
1417
- this._abortController.signal.removeEventListener('abort', abortConnect);
1418
- this._retries = 0;
1419
- this._send({"janus": "create"})
1420
- .then(json => {
1421
- this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
1422
- this._startKeepAlive();
1423
- return 1;
1424
- })
1425
- .then(() => this._createParticipant(userId))
1426
- .then(handle => {
1427
- this.handleId = handle.handleId;
1428
- return 1
1429
- })
1430
- .then(() => this._joinRoom(roomId, pin, userId, display))
1431
- .then(() => {
1432
- this._enableStatsWatch();
1433
- this._enableSubstreamAutoSelect();
1434
- this.isConnecting = false;
1435
- this.emit('joining', false);
1436
- resolve(this);
1437
- })
1438
- .catch(error => {
1439
- this.isConnecting = false;
1440
- this.emit('joining', false);
1441
- reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
1442
- });
1443
- };
1444
-
1445
- this.ws.onerror = (e) => {
1446
- this._abortController.signal.removeEventListener('abort', abortConnect);
1447
- this.isConnecting = false;
1448
- this.emit('joining', false);
1449
- reject({type: 'error', id: 14, message: 'ws connection error', data: e});
1450
- }
1451
-
1452
- this._abortController.signal.addEventListener('abort', abortConnect);
1453
-
1454
- });
1650
+ if(this.useWebsockets) {
1651
+ return this._webSocketConnection(false)
1652
+ }
1653
+ else {
1654
+ return this._httpConnection(false)
1655
+ }
1455
1656
  }
1456
1657
 
1457
1658
  disconnect() {
@@ -1789,7 +1990,7 @@ class RoomSession {
1789
1990
 
1790
1991
  _parseVideoStats(participantsStats) {
1791
1992
 
1792
- let statsToEmitt = [];
1993
+ let statsToEmit = [];
1793
1994
 
1794
1995
  for (const sourceStats of participantsStats) {
1795
1996
 
@@ -1865,7 +2066,7 @@ class RoomSession {
1865
2066
  handle.webrtcStuff.stats[mid].shift();
1866
2067
  }
1867
2068
 
1868
- statsToEmitt.push({
2069
+ statsToEmit.push({
1869
2070
  handleId: participantStats.handleId,
1870
2071
  stats,
1871
2072
  userId: decodeJanusDisplay(handle.userId)?.userId,
@@ -1875,7 +2076,7 @@ class RoomSession {
1875
2076
  }
1876
2077
  }
1877
2078
 
1878
- this.emit('rtcStats', statsToEmitt);
2079
+ this.emit('rtcStats', statsToEmit);
1879
2080
  }
1880
2081
 
1881
2082
  _getStats(type = null) {
@@ -2125,6 +2326,7 @@ class RoomSession {
2125
2326
  if(event.track.kind === 'video') {
2126
2327
  this.requestKeyFrame(handle.handleId, mid);
2127
2328
  }
2329
+
2128
2330
  this.emit(this._getAddParticipantEventName(handle.handleId), {
2129
2331
  tid: generateUUID(),
2130
2332
  mid,
@@ -2831,28 +3033,11 @@ class RoomSession {
2831
3033
  config.pc.addTrack(stream.getVideoTracks()[0], config.stream);
2832
3034
  }
2833
3035
  else {
2834
- if(adapter.browserDetails.browser !== 'firefox') {
2835
-
2836
- // standard
2837
- config.pc.addTransceiver(stream.getVideoTracks()[0], {
2838
- direction: 'sendonly',
2839
- streams: [config.stream],
2840
- sendEncodings: structuredClone(simulcastConfigForSource?.bitrates)
2841
- })
2842
- }
2843
- else {
2844
- // firefox
2845
- let transceiver = config.pc.addTransceiver(stream.getVideoTracks()[0], {
2846
- direction: 'sendonly',
2847
- streams: [config.stream]
2848
- });
2849
- let sender = transceiver ? transceiver.sender : null;
2850
- if(sender) {
2851
- let parameters = sender.getParameters() || {};
2852
- parameters.encodings = stream.getVideoTracks()[0].sendEncodings || structuredClone(simulcastConfigForSource?.bitrates);
2853
- sender.setParameters(parameters);
2854
- }
2855
- }
3036
+ config.pc.addTransceiver(stream.getVideoTracks()[0], {
3037
+ direction: 'sendonly',
3038
+ streams: [config.stream],
3039
+ sendEncodings: structuredClone(simulcastConfigForSource?.bitrates)
3040
+ })
2856
3041
  }
2857
3042
  needsNegotiation = true;
2858
3043
  }
@@ -3224,23 +3409,31 @@ class RoomSession {
3224
3409
  let config = handle.webrtcStuff;
3225
3410
  return new Promise((resolve, reject) => {
3226
3411
  let messageTimeoutId;
3227
- let abortResponse = () => {
3412
+
3413
+ let clearListeners = () => {
3228
3414
  clearTimeout(messageTimeoutId);
3229
3415
  this._abortController.signal.removeEventListener('abort', abortResponse);
3230
- this.ws.removeEventListener('message', parseResponse);
3416
+ this.off('longPollEvent', parseResponse);
3417
+ this.ws?.removeEventListener('message', parseResponse);
3418
+ };
3419
+
3420
+ let abortResponse = () => {
3421
+ clearListeners();
3231
3422
  reject('aborted');
3232
3423
  };
3424
+
3233
3425
  let parseResponse = (event) => {
3234
- let json = JSON.parse(event.data);
3426
+ let json = typeof event.data === 'string'
3427
+ ? JSON.parse(event.data)
3428
+ : event.data;
3429
+
3235
3430
  var sender = json["sender"];
3236
3431
  if(sender === handleId) {
3237
3432
  let plugindata = json["plugindata"] || {};
3238
3433
  let msg = plugindata["data"] || {};
3239
3434
  let substream = msg["substream"];
3240
3435
  if(substream !== undefined && substream !== null && (mid !== undefined ? msg["mid"] === mid : true)) {
3241
- clearTimeout(messageTimeoutId);
3242
- this._abortController.signal.removeEventListener('abort', abortResponse);
3243
- this.ws.removeEventListener('message', parseResponse);
3436
+ clearListeners();
3244
3437
  resolve({substream, sender});
3245
3438
  }
3246
3439
  }
@@ -3280,11 +3473,11 @@ class RoomSession {
3280
3473
  config.overriddenSimulcastMode[mid]['mode'] = "manual";
3281
3474
  }
3282
3475
 
3283
- this.ws.addEventListener('message', parseResponse);
3476
+ this.on('longPollEvent', parseResponse);
3477
+ this.ws?.addEventListener('message', parseResponse);
3284
3478
  this._abortController.signal.addEventListener('abort', abortResponse);
3285
3479
  messageTimeoutId = setTimeout(() => {
3286
- this._abortController.signal.removeEventListener('abort', abortResponse);
3287
- this.ws.removeEventListener('message', parseResponse);
3480
+ clearListeners();
3288
3481
  reject('timeout');
3289
3482
  }, 10000);
3290
3483