@reactoo/watchtogether-sdk-js 2.7.89 → 2.7.91
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 +1604 -860
- package/dist/watchtogether-sdk.js.map +1 -1
- package/dist/watchtogether-sdk.min.js +2 -2
- package/example/index.html +1 -1
- package/package.json +1 -1
- package/src/models/room-session.js +1 -0
- package/src/modules/wt-room.js +343 -138
package/src/modules/wt-room.js
CHANGED
|
@@ -251,14 +251,15 @@ 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;
|
|
257
|
+
this.isSupposeToBeConnected = false;
|
|
256
258
|
this.isRestarting = false;
|
|
257
259
|
this.isConnecting = false;
|
|
258
260
|
this.isDisconnecting = false;
|
|
259
261
|
this.isConnected = false;
|
|
260
262
|
this.isPublished = false;
|
|
261
|
-
this.isReclaiming = false;
|
|
262
263
|
this.isStreaming = false;
|
|
263
264
|
this.isMuted = [];
|
|
264
265
|
this.isVideoEnabled = 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
|
-
|
|
435
|
-
|
|
518
|
+
_sendHTTP(request = {}, ignoreResponse = false, dontResolveOnAck = false, retry = 0) {
|
|
436
519
|
let transaction = RoomSession.randomString(12);
|
|
437
520
|
let requestData = {
|
|
438
521
|
...request,
|
|
439
522
|
transaction,
|
|
440
|
-
token: this.token,
|
|
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) {
|
|
539
|
+
let transaction = RoomSession.randomString(12);
|
|
540
|
+
let requestData = {
|
|
541
|
+
...request,
|
|
542
|
+
transaction,
|
|
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,50 @@ 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
|
+
|
|
622
|
+
if(!this.isSupposeToBeConnected) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
let longpoll = this.server + "/" + this.sessionId + "?rid=" + new Date().getTime();
|
|
628
|
+
if(this._maxev)
|
|
629
|
+
longpoll = longpoll + "&maxev=" + this._maxev;
|
|
630
|
+
if(this.token)
|
|
631
|
+
longpoll = longpoll + "&token=" + encodeURIComponent(this.token);
|
|
632
|
+
if(this.apisecret)
|
|
633
|
+
longpoll = longpoll + "&apisecret=" + encodeURIComponent(this.apisecret);
|
|
634
|
+
|
|
635
|
+
this._httpAPICall(longpoll, {
|
|
636
|
+
verb: 'GET',
|
|
637
|
+
timeout: this._longPollTimeout
|
|
638
|
+
})
|
|
639
|
+
.then(this._handleWsEvents.bind(this))
|
|
640
|
+
.catch(() => {
|
|
641
|
+
|
|
642
|
+
this._retries++;
|
|
643
|
+
if(this._retries > this._maxRetries) {
|
|
644
|
+
if (this.sessiontype === 'reactooroom') {
|
|
645
|
+
this.disconnect(true);
|
|
646
|
+
} else if (this.sessiontype === 'streaming') {
|
|
647
|
+
this.stopStream();
|
|
648
|
+
}
|
|
649
|
+
this.emit('error', {type: 'error', id: 33, message: 'Lost connection to server', data: null});
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
this._longPoll();
|
|
653
|
+
})
|
|
654
|
+
}
|
|
506
655
|
|
|
507
656
|
_connectionClosed() {
|
|
508
657
|
|
|
@@ -555,16 +704,36 @@ class RoomSession {
|
|
|
555
704
|
|
|
556
705
|
this._keepAliveId = setTimeout(() => {
|
|
557
706
|
this._startKeepAlive();
|
|
558
|
-
},
|
|
707
|
+
}, this._keepAlivePeriod);
|
|
559
708
|
}
|
|
560
709
|
|
|
561
710
|
_stopKeepAlive() {
|
|
562
711
|
clearTimeout(this._keepAliveId);
|
|
563
712
|
}
|
|
564
713
|
|
|
565
|
-
_handleWsEvents(event) {
|
|
714
|
+
_handleWsEvents(event, skipPoll = false) {
|
|
715
|
+
|
|
716
|
+
this._retries = 0;
|
|
717
|
+
|
|
718
|
+
// we have a response from long poll, that means we need to run it again
|
|
719
|
+
if(!this.useWebsockets && !skipPoll) {
|
|
720
|
+
this._longPoll();
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if(!this.useWebsockets && skipPoll) {
|
|
724
|
+
// we need to fire those events into the wild
|
|
725
|
+
this.emit('longPollEvent', event);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if(Array.isArray(event)) {
|
|
729
|
+
event.forEach(ev => this._handleWsEvents({data:ev}, true));
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
let json = typeof event.data === 'string'
|
|
734
|
+
? JSON.parse(event.data)
|
|
735
|
+
: event.data;
|
|
566
736
|
|
|
567
|
-
let json = JSON.parse(event.data);
|
|
568
737
|
var sender = json["sender"];
|
|
569
738
|
var type = json["janus"];
|
|
570
739
|
|
|
@@ -1274,14 +1443,15 @@ class RoomSession {
|
|
|
1274
1443
|
: Promise.resolve();
|
|
1275
1444
|
}
|
|
1276
1445
|
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
_reconnect() {
|
|
1446
|
+
_webSocketConnection(reclaim = false) {
|
|
1280
1447
|
|
|
1281
|
-
if (this.
|
|
1282
|
-
return Promise.
|
|
1448
|
+
if (this.isConnecting) {
|
|
1449
|
+
return Promise.reject({type: 'warning', id: 16, message: 'connection establishment already in progress'});
|
|
1283
1450
|
}
|
|
1284
1451
|
|
|
1452
|
+
this.isConnecting = true;
|
|
1453
|
+
this.emit('joining', true);
|
|
1454
|
+
|
|
1285
1455
|
if (this.ws) {
|
|
1286
1456
|
this._wipeListeners();
|
|
1287
1457
|
if (this.ws.readyState === 1) {
|
|
@@ -1289,60 +1459,153 @@ class RoomSession {
|
|
|
1289
1459
|
}
|
|
1290
1460
|
}
|
|
1291
1461
|
this._stopKeepAlive();
|
|
1292
|
-
|
|
1293
|
-
this.emit('joining', true);
|
|
1462
|
+
|
|
1294
1463
|
return new Promise((resolve, reject) => {
|
|
1295
1464
|
|
|
1296
|
-
|
|
1297
|
-
|
|
1465
|
+
this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
|
|
1466
|
+
this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
|
|
1467
|
+
|
|
1468
|
+
let abortConnect = () => {
|
|
1469
|
+
this._abortController.signal.removeEventListener('abort', abortConnect);
|
|
1298
1470
|
this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
|
|
1299
1471
|
this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
|
|
1300
1472
|
this.ws.onopen = null;
|
|
1301
1473
|
this.ws.onerror = null;
|
|
1302
|
-
this.
|
|
1474
|
+
this.isConnecting = false;
|
|
1303
1475
|
this.emit('joining', false);
|
|
1304
|
-
reject({type: 'warning', id: 17, message: 'Connection cancelled'
|
|
1476
|
+
reject({type: 'warning', id: 17, message: 'Connection cancelled'});
|
|
1305
1477
|
};
|
|
1306
1478
|
|
|
1307
1479
|
this.ws = new WebSocket(this.server, 'janus-protocol');
|
|
1308
|
-
this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
|
|
1309
|
-
this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
|
|
1310
1480
|
this.ws.addEventListener('close', this.__connectionClosedBoundFn);
|
|
1311
1481
|
this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
|
|
1482
|
+
|
|
1312
1483
|
this.ws.onopen = () => {
|
|
1313
|
-
this._abortController.signal.removeEventListener('abort',
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1484
|
+
this._abortController.signal.removeEventListener('abort', abortConnect);
|
|
1485
|
+
|
|
1486
|
+
if(!reclaim) {
|
|
1487
|
+
|
|
1488
|
+
this._send({"janus": "create"})
|
|
1489
|
+
.then(json => {
|
|
1490
|
+
this._retries = 0;
|
|
1491
|
+
this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
|
|
1492
|
+
this._startKeepAlive();
|
|
1493
|
+
return 1;
|
|
1494
|
+
})
|
|
1495
|
+
.then(() => this._createParticipant(this.userId))
|
|
1496
|
+
.then(handle => {
|
|
1497
|
+
this.handleId = handle.handleId;
|
|
1498
|
+
return 1
|
|
1499
|
+
})
|
|
1500
|
+
.then(() => this._joinRoom(this.roomId, this.pin, this.userId, this.display))
|
|
1501
|
+
.then(() => {
|
|
1502
|
+
this._enableStatsWatch();
|
|
1503
|
+
this._enableSubstreamAutoSelect();
|
|
1504
|
+
this.isConnecting = false;
|
|
1505
|
+
this.emit('joining', false);
|
|
1506
|
+
resolve(this);
|
|
1507
|
+
})
|
|
1508
|
+
.catch(error => {
|
|
1509
|
+
this.isConnecting = false;
|
|
1510
|
+
this.emit('joining', false);
|
|
1511
|
+
reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
|
|
1512
|
+
});
|
|
1513
|
+
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
else {
|
|
1517
|
+
this._send({"janus": "claim"})
|
|
1518
|
+
.then(json => {
|
|
1519
|
+
this._retries = 0;
|
|
1520
|
+
this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
|
|
1521
|
+
this._startKeepAlive();
|
|
1522
|
+
this.isConnecting = false;
|
|
1523
|
+
this.emit('joining', false);
|
|
1524
|
+
resolve(json);
|
|
1525
|
+
})
|
|
1526
|
+
.catch(error => {
|
|
1527
|
+
this.isConnecting = false;
|
|
1528
|
+
this.emit('joining', false);
|
|
1529
|
+
reject({type: 'error', id: 11, message: 'reconnection error', data: error})
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1328
1533
|
};
|
|
1329
1534
|
|
|
1330
|
-
// this is called before 'close' event callback so it doesn't break reconnect loop
|
|
1331
1535
|
this.ws.onerror = (e) => {
|
|
1332
|
-
this._abortController.signal.removeEventListener('abort',
|
|
1333
|
-
this.
|
|
1536
|
+
this._abortController.signal.removeEventListener('abort', abortConnect);
|
|
1537
|
+
this.isConnecting = false;
|
|
1334
1538
|
this.emit('joining', false);
|
|
1335
|
-
reject({type: '
|
|
1539
|
+
reject({type: 'error', id: 14, message: 'ws connection error', data: e});
|
|
1336
1540
|
}
|
|
1337
1541
|
|
|
1338
|
-
this._abortController.signal.addEventListener('abort',
|
|
1542
|
+
this._abortController.signal.addEventListener('abort', abortConnect);
|
|
1543
|
+
|
|
1339
1544
|
});
|
|
1340
1545
|
}
|
|
1341
1546
|
|
|
1547
|
+
_httpConnection(reclaim = false) {
|
|
1548
|
+
if(!reclaim) {
|
|
1549
|
+
return this._send({"janus": "create"})
|
|
1550
|
+
.then(json => {
|
|
1551
|
+
this._retries = 0;
|
|
1552
|
+
this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
|
|
1553
|
+
this._startKeepAlive();
|
|
1554
|
+
return 1;
|
|
1555
|
+
})
|
|
1556
|
+
.then(() => this._createParticipant(this.userId))
|
|
1557
|
+
.then(handle => {
|
|
1558
|
+
this.handleId = handle.handleId;
|
|
1559
|
+
return 1
|
|
1560
|
+
})
|
|
1561
|
+
.then(() => this._joinRoom(this.roomId, this.pin, this.userId, this.display))
|
|
1562
|
+
.then(() => {
|
|
1563
|
+
this._enableStatsWatch();
|
|
1564
|
+
this._enableSubstreamAutoSelect();
|
|
1565
|
+
this._longPoll();
|
|
1566
|
+
this.isConnecting = false;
|
|
1567
|
+
this.emit('joining', false);
|
|
1568
|
+
return Promise.resolve(this);
|
|
1569
|
+
})
|
|
1570
|
+
.catch(error => {
|
|
1571
|
+
this.isConnecting = false;
|
|
1572
|
+
this.emit('joining', false);
|
|
1573
|
+
return Promise.reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
|
|
1574
|
+
});
|
|
1575
|
+
}
|
|
1576
|
+
else {
|
|
1577
|
+
return this._send({"janus": "claim"})
|
|
1578
|
+
.then(json => {
|
|
1579
|
+
this._retries = 0;
|
|
1580
|
+
this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
|
|
1581
|
+
this._startKeepAlive();
|
|
1582
|
+
this.isConnecting = false;
|
|
1583
|
+
this.emit('joining', false);
|
|
1584
|
+
return Promise.resolve(json);
|
|
1585
|
+
})
|
|
1586
|
+
.catch(error => {
|
|
1587
|
+
this.isConnecting = false;
|
|
1588
|
+
this.emit('joining', false);
|
|
1589
|
+
return Promise.reject({type: 'error', id: 11, message: 'reconnection error', data: error})
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
// internal reconnect
|
|
1596
|
+
_reconnect() {
|
|
1597
|
+
if(this.useWebsockets) {
|
|
1598
|
+
return this._webSocketConnection(true)
|
|
1599
|
+
}
|
|
1600
|
+
else {
|
|
1601
|
+
return this._httpConnection(true)
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1342
1604
|
connect(
|
|
1343
1605
|
roomId,
|
|
1344
1606
|
pin,
|
|
1345
1607
|
server,
|
|
1608
|
+
protocol,
|
|
1346
1609
|
iceServers,
|
|
1347
1610
|
token,
|
|
1348
1611
|
display,
|
|
@@ -1355,18 +1618,17 @@ class RoomSession {
|
|
|
1355
1618
|
enableDtx = false
|
|
1356
1619
|
) {
|
|
1357
1620
|
|
|
1621
|
+
this.isSupposeToBeConnected = true;
|
|
1622
|
+
|
|
1358
1623
|
if (this.isConnecting) {
|
|
1359
1624
|
return Promise.reject({type: 'warning', id: 16, message: 'connection already in progress'});
|
|
1360
1625
|
}
|
|
1361
1626
|
|
|
1362
|
-
if (this.ws) {
|
|
1363
|
-
this._wipeListeners();
|
|
1364
|
-
}
|
|
1365
|
-
this._stopKeepAlive();
|
|
1366
1627
|
this._abortController = new AbortController();
|
|
1367
1628
|
|
|
1368
1629
|
this.sessionId = null;
|
|
1369
1630
|
this.server = server;
|
|
1631
|
+
this.protocol = protocol;
|
|
1370
1632
|
this.iceServers = iceServers;
|
|
1371
1633
|
this.token = token;
|
|
1372
1634
|
this.roomId = roomId;
|
|
@@ -1376,10 +1638,10 @@ class RoomSession {
|
|
|
1376
1638
|
this.webrtcVersion = webrtcVersion;
|
|
1377
1639
|
this.initialBitrate = initialBitrate;
|
|
1378
1640
|
this.recordingFilename = recordingFilename;
|
|
1379
|
-
this.isConnecting = true;
|
|
1380
1641
|
this.enableDtx = enableDtx;
|
|
1381
1642
|
this.simulcast = simulcast;
|
|
1382
1643
|
this.simulcastSettings = structuredClone(simulcastSettings);
|
|
1644
|
+
this.useWebsockets = this.protocol === 'ws' || this.protocol === 'wss';
|
|
1383
1645
|
|
|
1384
1646
|
// sort simulcast bitrates
|
|
1385
1647
|
if(this.simulcastSettings && typeof this.simulcastSettings === 'object' && Object.keys(this.simulcastSettings).length) {
|
|
@@ -1393,69 +1655,18 @@ class RoomSession {
|
|
|
1393
1655
|
});
|
|
1394
1656
|
}
|
|
1395
1657
|
|
|
1396
|
-
this.
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
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
|
-
});
|
|
1658
|
+
if(this.useWebsockets) {
|
|
1659
|
+
return this._webSocketConnection(false)
|
|
1660
|
+
}
|
|
1661
|
+
else {
|
|
1662
|
+
return this._httpConnection(false)
|
|
1663
|
+
}
|
|
1455
1664
|
}
|
|
1456
1665
|
|
|
1457
1666
|
disconnect() {
|
|
1458
1667
|
|
|
1668
|
+
this.isSupposeToBeConnected = false;
|
|
1669
|
+
|
|
1459
1670
|
if (this.isDisconnecting) {
|
|
1460
1671
|
return Promise.resolve();
|
|
1461
1672
|
}
|
|
@@ -1488,6 +1699,8 @@ class RoomSession {
|
|
|
1488
1699
|
|
|
1489
1700
|
startStream(streamId, server, iceServers, token, userId) {
|
|
1490
1701
|
|
|
1702
|
+
this.isSupposeToBeConnected = true;
|
|
1703
|
+
|
|
1491
1704
|
if (this.isConnecting) {
|
|
1492
1705
|
return Promise.reject({type: 'warning', id: 16, message: 'connection error', data: 'Connection is in progress'});
|
|
1493
1706
|
}
|
|
@@ -1789,7 +2002,7 @@ class RoomSession {
|
|
|
1789
2002
|
|
|
1790
2003
|
_parseVideoStats(participantsStats) {
|
|
1791
2004
|
|
|
1792
|
-
let
|
|
2005
|
+
let statsToEmit = [];
|
|
1793
2006
|
|
|
1794
2007
|
for (const sourceStats of participantsStats) {
|
|
1795
2008
|
|
|
@@ -1865,7 +2078,7 @@ class RoomSession {
|
|
|
1865
2078
|
handle.webrtcStuff.stats[mid].shift();
|
|
1866
2079
|
}
|
|
1867
2080
|
|
|
1868
|
-
|
|
2081
|
+
statsToEmit.push({
|
|
1869
2082
|
handleId: participantStats.handleId,
|
|
1870
2083
|
stats,
|
|
1871
2084
|
userId: decodeJanusDisplay(handle.userId)?.userId,
|
|
@@ -1875,7 +2088,7 @@ class RoomSession {
|
|
|
1875
2088
|
}
|
|
1876
2089
|
}
|
|
1877
2090
|
|
|
1878
|
-
this.emit('rtcStats',
|
|
2091
|
+
this.emit('rtcStats', statsToEmit);
|
|
1879
2092
|
}
|
|
1880
2093
|
|
|
1881
2094
|
_getStats(type = null) {
|
|
@@ -2125,6 +2338,7 @@ class RoomSession {
|
|
|
2125
2338
|
if(event.track.kind === 'video') {
|
|
2126
2339
|
this.requestKeyFrame(handle.handleId, mid);
|
|
2127
2340
|
}
|
|
2341
|
+
|
|
2128
2342
|
this.emit(this._getAddParticipantEventName(handle.handleId), {
|
|
2129
2343
|
tid: generateUUID(),
|
|
2130
2344
|
mid,
|
|
@@ -2831,28 +3045,11 @@ class RoomSession {
|
|
|
2831
3045
|
config.pc.addTrack(stream.getVideoTracks()[0], config.stream);
|
|
2832
3046
|
}
|
|
2833
3047
|
else {
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
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
|
-
}
|
|
3048
|
+
config.pc.addTransceiver(stream.getVideoTracks()[0], {
|
|
3049
|
+
direction: 'sendonly',
|
|
3050
|
+
streams: [config.stream],
|
|
3051
|
+
sendEncodings: structuredClone(simulcastConfigForSource?.bitrates)
|
|
3052
|
+
})
|
|
2856
3053
|
}
|
|
2857
3054
|
needsNegotiation = true;
|
|
2858
3055
|
}
|
|
@@ -3224,23 +3421,31 @@ class RoomSession {
|
|
|
3224
3421
|
let config = handle.webrtcStuff;
|
|
3225
3422
|
return new Promise((resolve, reject) => {
|
|
3226
3423
|
let messageTimeoutId;
|
|
3227
|
-
|
|
3424
|
+
|
|
3425
|
+
let clearListeners = () => {
|
|
3228
3426
|
clearTimeout(messageTimeoutId);
|
|
3229
3427
|
this._abortController.signal.removeEventListener('abort', abortResponse);
|
|
3230
|
-
this.
|
|
3428
|
+
this.off('longPollEvent', parseResponse);
|
|
3429
|
+
this.ws?.removeEventListener('message', parseResponse);
|
|
3430
|
+
};
|
|
3431
|
+
|
|
3432
|
+
let abortResponse = () => {
|
|
3433
|
+
clearListeners();
|
|
3231
3434
|
reject('aborted');
|
|
3232
3435
|
};
|
|
3436
|
+
|
|
3233
3437
|
let parseResponse = (event) => {
|
|
3234
|
-
let json =
|
|
3438
|
+
let json = typeof event.data === 'string'
|
|
3439
|
+
? JSON.parse(event.data)
|
|
3440
|
+
: event.data;
|
|
3441
|
+
|
|
3235
3442
|
var sender = json["sender"];
|
|
3236
3443
|
if(sender === handleId) {
|
|
3237
3444
|
let plugindata = json["plugindata"] || {};
|
|
3238
3445
|
let msg = plugindata["data"] || {};
|
|
3239
3446
|
let substream = msg["substream"];
|
|
3240
3447
|
if(substream !== undefined && substream !== null && (mid !== undefined ? msg["mid"] === mid : true)) {
|
|
3241
|
-
|
|
3242
|
-
this._abortController.signal.removeEventListener('abort', abortResponse);
|
|
3243
|
-
this.ws.removeEventListener('message', parseResponse);
|
|
3448
|
+
clearListeners();
|
|
3244
3449
|
resolve({substream, sender});
|
|
3245
3450
|
}
|
|
3246
3451
|
}
|
|
@@ -3280,11 +3485,11 @@ class RoomSession {
|
|
|
3280
3485
|
config.overriddenSimulcastMode[mid]['mode'] = "manual";
|
|
3281
3486
|
}
|
|
3282
3487
|
|
|
3283
|
-
this.
|
|
3488
|
+
this.on('longPollEvent', parseResponse);
|
|
3489
|
+
this.ws?.addEventListener('message', parseResponse);
|
|
3284
3490
|
this._abortController.signal.addEventListener('abort', abortResponse);
|
|
3285
3491
|
messageTimeoutId = setTimeout(() => {
|
|
3286
|
-
|
|
3287
|
-
this.ws.removeEventListener('message', parseResponse);
|
|
3492
|
+
clearListeners();
|
|
3288
3493
|
reject('timeout');
|
|
3289
3494
|
}, 10000);
|
|
3290
3495
|
|