@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/dist/watchtogether-sdk.js +1597 -859
- package/dist/watchtogether-sdk.js.map +1 -1
- package/dist/watchtogether-sdk.min.js +2 -2
- package/package.json +1 -1
- package/src/models/iot.js +4 -0
- package/src/models/room-session.js +1 -0
- package/src/modules/wt-room.js +330 -137
package/package.json
CHANGED
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,
|
package/src/modules/wt-room.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
-
},
|
|
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
|
-
|
|
1440
|
+
_webSocketConnection(reclaim = false) {
|
|
1278
1441
|
|
|
1279
|
-
|
|
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
|
-
|
|
1293
|
-
this.emit('joining', true);
|
|
1456
|
+
|
|
1294
1457
|
return new Promise((resolve, reject) => {
|
|
1295
1458
|
|
|
1296
|
-
|
|
1297
|
-
|
|
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.
|
|
1468
|
+
this.isConnecting = false;
|
|
1303
1469
|
this.emit('joining', false);
|
|
1304
|
-
reject({type: 'warning', id: 17, message: 'Connection cancelled'
|
|
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',
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
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',
|
|
1333
|
-
this.
|
|
1530
|
+
this._abortController.signal.removeEventListener('abort', abortConnect);
|
|
1531
|
+
this.isConnecting = false;
|
|
1334
1532
|
this.emit('joining', false);
|
|
1335
|
-
reject({type: '
|
|
1533
|
+
reject({type: 'error', id: 14, message: 'ws connection error', data: e});
|
|
1336
1534
|
}
|
|
1337
1535
|
|
|
1338
|
-
this._abortController.signal.addEventListener('abort',
|
|
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.
|
|
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
|
-
});
|
|
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
|
|
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
|
-
|
|
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',
|
|
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
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
3412
|
+
|
|
3413
|
+
let clearListeners = () => {
|
|
3228
3414
|
clearTimeout(messageTimeoutId);
|
|
3229
3415
|
this._abortController.signal.removeEventListener('abort', abortResponse);
|
|
3230
|
-
this.
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
3476
|
+
this.on('longPollEvent', parseResponse);
|
|
3477
|
+
this.ws?.addEventListener('message', parseResponse);
|
|
3284
3478
|
this._abortController.signal.addEventListener('abort', abortResponse);
|
|
3285
3479
|
messageTimeoutId = setTimeout(() => {
|
|
3286
|
-
|
|
3287
|
-
this.ws.removeEventListener('message', parseResponse);
|
|
3480
|
+
clearListeners();
|
|
3288
3481
|
reject('timeout');
|
|
3289
3482
|
}, 10000);
|
|
3290
3483
|
|