@reactoo/watchtogether-sdk-js 2.8.0-beta.3 → 2.8.0-beta.5

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.
@@ -576,6 +576,10 @@
576
576
  Instance.room.getSessionByConstructId(constructId).setRestrictSubscribeToUserIds(userIds)
577
577
  }
578
578
 
579
+ window.restart = function () {
580
+ Instance.room.getSessionByConstructId(constructId).restart()
581
+ }
582
+
579
583
 
580
584
  </script>
581
585
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactoo/watchtogether-sdk-js",
3
- "version": "2.8.0-beta.3",
3
+ "version": "2.8.0-beta.5",
4
4
  "description": "Javascript SDK for Reactoo",
5
5
  "main": "dist/watchtogether-sdk.min.js",
6
6
  "module": "dist/watchtogether-sdk.min.js",
@@ -156,22 +156,24 @@ let roomSession = function ({roomId, pinHash, role, options = {}}, room, wt) {
156
156
  room.isRestarting = true;
157
157
 
158
158
  let wasPublished = room.isPublished;
159
- let handle = room._getHandle(room.handleId);
160
- let stream = null;
161
- if (handle?.webrtcStuff?.stream && wasPublished) {
162
- stream = handle.webrtcStuff.stream;
163
- }
159
+ let streams = room.getLocalStreams();
164
160
 
165
161
  return this.disconnect()
166
162
  .then(() => wait(1000)) //TODO: remove 1000ms wait by waiting for proper events from janus
167
163
  .then(() => this.connect({reactooRoomId}))
168
164
  .then(() => {
169
- if (isObserver) {
165
+ if(streams.length) {
166
+ return streams.reduce((promise, stream) => {
167
+ return promise.then(() => {
168
+ return this.publishLocal(stream.stream, stream.source);
169
+ });
170
+ }, Promise.resolve())
171
+
172
+ } else if (wasPublished) {
170
173
  return this.publishLocal(null);
171
- } else if (stream) {
172
- return this.publishLocal(stream);
173
- } else
174
+ } else {
174
175
  return Promise.resolve()
176
+ }
175
177
  })
176
178
  .then(() => {
177
179
  room.isRestarting = false;
@@ -278,6 +278,7 @@ class RoomSession {
278
278
  // helper flags
279
279
 
280
280
  this.isSupposeToBeConnected = false;
281
+ this.isRestarting = false; // used from outside
281
282
  this.isConnecting = false;
282
283
  this.isEstablishingConnection = false;
283
284
  this.isDisconnecting = false;
@@ -406,6 +407,13 @@ class RoomSession {
406
407
  }
407
408
  }
408
409
 
410
+ #hasAttendeeInCache(id) {
411
+ if(this.#subscriberHandle) {
412
+ return !!this.#subscriberHandle.webrtcStuff.userIdToDisplay[id];
413
+ }
414
+ return false
415
+ }
416
+
409
417
  #getCachedAttendeeIds() {
410
418
  return Object.keys(this.#subscriberHandle?.webrtcStuff?.userIdToDisplay || {});
411
419
  }
@@ -448,7 +456,7 @@ class RoomSession {
448
456
  });
449
457
  }
450
458
 
451
- #emitRemoteFeedUpdate(mid, {feedRemoval = false, addingTrack = false, removingTrack = false, track = null, source = null, attendee = null} = {}) {
459
+ #emitRemoteFeedUpdate(mid, {forceEmit = false,feedRemoval = false, addingTrack = false, removingTrack = false, track = null, source = null, attendee = null} = {}) {
452
460
 
453
461
  const transceiverData = this.#getTransceiverDataByMid(mid);
454
462
 
@@ -462,7 +470,7 @@ class RoomSession {
462
470
  description = JSON.parse(transceiverData.feed_description);
463
471
  } catch (e) {}
464
472
 
465
- if(!this.#shouldEmitFeedUpdate(parsedDisplay)) {
473
+ if(!this.#shouldEmitFeedUpdate(parsedDisplay) && !forceEmit && !removingTrack) {
466
474
  this._log('Not emitting feed update for', display, 'because of subscription rules');
467
475
  // we don't want to emit this event
468
476
  return;
@@ -513,7 +521,8 @@ class RoomSession {
513
521
  const display = this.#getDisplayById(id);
514
522
  const parsedDisplay = decodeJanusDisplay(display);
515
523
 
516
- if(!this.#shouldEmitFeedUpdate(parsedDisplay)) {
524
+ // we sometimes need to force emit, or emit when we unsubscribed and we're removing tracks
525
+ if(!this.#shouldEmitFeedUpdate(parsedDisplay, id) && !forceEmit && !removingTrack) {
517
526
  this._log('Not emitting feed update for', display, 'because of subscription rules');
518
527
  // we don't want to emit this event
519
528
  return;
@@ -654,6 +663,7 @@ class RoomSession {
654
663
  const subscribe = [];
655
664
  const unsubscribe = [];
656
665
  const flatSourceMap = [];
666
+ const forceEmitFeedRemoval = []
657
667
 
658
668
  for (let index in publishers) {
659
669
  if(publishers[index]["dummy"])
@@ -692,6 +702,10 @@ class RoomSession {
692
702
  if(isSubscribed) {
693
703
  unsubscribe.push({feed: id, mid: mid});
694
704
  this.#removeFromSubscribeMap(id, mid);
705
+ // we need to get rid of feed if we we're subscribed to it
706
+ if(forceEmitFeedRemoval.indexOf(id) === -1) {
707
+ forceEmitFeedRemoval.push(id);
708
+ }
695
709
  }
696
710
  continue;
697
711
  }
@@ -703,6 +717,9 @@ class RoomSession {
703
717
  }
704
718
  }
705
719
 
720
+ // we need to get rid of feed if we we're subscribed to it
721
+ forceEmitFeedRemoval.forEach(id => this.#emitRemoteFeedUpdate(null, {feedRemoval: true, forceEmit: true, attendee: {id:id}}))
722
+
706
723
  // check if we're subscribed to any mid that is no longer available in sources
707
724
 
708
725
  Object.keys(subscribedTo).forEach(id => {
@@ -784,7 +801,7 @@ class RoomSession {
784
801
  // feed_id === id of participant
785
802
 
786
803
  #updateTransceiverMap(handleId, streams = []) {
787
- this._log('Updating current transceiver map', 'Is me: ' + handleId === this.#publisherHandle.handleId, handleId, streams);
804
+ this._log('Updating current transceiver map', 'Is me: ' + handleId === this.#publisherHandle?.handleId, handleId, streams);
788
805
  let handle = this.#getHandle(handleId);
789
806
  if (!handle) {
790
807
  this.emit('error', {
@@ -1115,12 +1132,12 @@ class RoomSession {
1115
1132
  } else if (type === "webrtcup") {
1116
1133
  //none universal
1117
1134
  } else if (type === "hangup") {
1118
- this._log('hangup on', handle.handleId, handle.handleId === this.#publisherHandle.handleId, json);
1135
+ this._log('hangup on', handle.handleId, handle.handleId === this.handleId, json);
1119
1136
  if(this.#getHandle(handle.handleId)) {
1120
1137
  this.#cleanupHandle(handle.handleId, true).catch(() => {});
1121
1138
  }
1122
1139
  } else if (type === "detached") {
1123
- this._log('detached on', handle.handleId, handle.handleId === this.#publisherHandle.handleId, json);
1140
+ this._log('detached on', handle.handleId, handle.handleId === this.handleId, json);
1124
1141
  if(this.#getHandle(handle.handleId)) {
1125
1142
  this.#destroyHandle(handle.handleId).catch(() => {});
1126
1143
  }
@@ -1142,7 +1159,7 @@ class RoomSession {
1142
1159
 
1143
1160
  // LOCAL
1144
1161
 
1145
- if (sender === this.#publisherHandle.handleId) {
1162
+ if (sender === this.#publisherHandle?.handleId) {
1146
1163
  if (type === "event") {
1147
1164
 
1148
1165
  var plugindata = json["plugindata"] || {};
@@ -1213,7 +1230,7 @@ class RoomSession {
1213
1230
 
1214
1231
 
1215
1232
  if (leaving === 'ok') {
1216
- this._log('leaving', this.#publisherHandle.handleId, 'this is us');
1233
+ this._log('leaving', this.#publisherHandle?.handleId, 'this is us');
1217
1234
 
1218
1235
  this.#emitLocalFeedUpdate({feedRemoval: true});
1219
1236
 
@@ -1235,8 +1252,8 @@ class RoomSession {
1235
1252
  }
1236
1253
 
1237
1254
  if (unpublished === 'ok') {
1238
- this._log('unpublished', this.#publisherHandle.handleId, 'this is us');
1239
- this.#cleanupHandle(this.#publisherHandle.handleId, true).catch(() => {});
1255
+ this._log('unpublished', this.#publisherHandle?.handleId, 'this is us');
1256
+ this.#cleanupHandle(this.#publisherHandle?.handleId, true).catch(() => {});
1240
1257
 
1241
1258
  } else if (unpublished) {
1242
1259
  this._log('unpublished', unpublished);
@@ -1274,7 +1291,7 @@ class RoomSession {
1274
1291
  }
1275
1292
 
1276
1293
  if (jsep !== undefined && jsep !== null) {
1277
- this.#webrtcPeer(this.#publisherHandle.handleId, jsep)
1294
+ this.#webrtcPeer(this.#publisherHandle?.handleId, jsep)
1278
1295
  .catch(err => {
1279
1296
  this.emit('error', err);
1280
1297
  });
@@ -1288,7 +1305,7 @@ class RoomSession {
1288
1305
 
1289
1306
  this._log('Configuring bitrate: ' + this.initialBitrate);
1290
1307
  if (this.initialBitrate > 0) {
1291
- this.sendMessage(this.#publisherHandle.handleId, {
1308
+ this.sendMessage(this.#publisherHandle?.handleId, {
1292
1309
  "body": {
1293
1310
  "request": "configure",
1294
1311
  "bitrate": this.initialBitrate
@@ -1363,7 +1380,9 @@ class RoomSession {
1363
1380
  config.dataChannelOpen = this.defaultDataChannelLabel === data?.label && data?.state === 'open';
1364
1381
  }
1365
1382
 
1366
- if (handleId === this.#publisherHandle.handleId && this.defaultDataChannelLabel === data?.label) {
1383
+
1384
+
1385
+ if (handleId === this.handleId && this.defaultDataChannelLabel === data?.label) {
1367
1386
  this._isDataChannelOpen = data?.state === 'open';
1368
1387
  this.emit('dataChannel', data?.state === 'open');
1369
1388
  }
@@ -1384,13 +1403,13 @@ class RoomSession {
1384
1403
  config.dataChannelOpen = false;
1385
1404
  }
1386
1405
  }
1387
- if (handleId === this.#publisherHandle.handleId && this.defaultDataChannelLabel === data.label) {
1406
+ if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {
1388
1407
  this._isDataChannelOpen = false;
1389
1408
  this.emit('dataChannel', false);
1390
1409
  }
1391
1410
  }
1392
1411
 
1393
- if (handleId === this.#publisherHandle.handleId && type === 'message') {
1412
+ if (handleId === this.handleId && type === 'message') {
1394
1413
 
1395
1414
  let d = null;
1396
1415
 
@@ -1474,18 +1493,24 @@ class RoomSession {
1474
1493
 
1475
1494
  try {
1476
1495
  if (handle.webrtcStuff.stream) {
1477
- if(!this.isConnecting) {
1478
- handle.webrtcStuff.stream?.getTracks().forEach(track => track.stop());
1496
+
1497
+ if(this.isRestarting && handleId === this.handleId) {
1498
+ handle.webrtcStuff.stream?.getTracks().forEach(track => track.onended = null);
1479
1499
  }
1480
1500
  else {
1481
- handle.webrtcStuff.stream?.getTracks().forEach(track => track.onended = null);
1501
+ handle.webrtcStuff.stream?.getTracks().forEach(track => track.stop());
1482
1502
  }
1503
+
1483
1504
  }
1484
1505
  if(handle.webrtcStuff?.tracks?.length > 0) {
1485
1506
  handle.webrtcStuff.tracks.forEach(track => {
1486
1507
  if (track) {
1487
- track.stop();
1488
- track.onended = null;
1508
+ if(this.isRestarting && handleId === this.handleId) {
1509
+ track.onended = null;
1510
+ }
1511
+ else {
1512
+ track.stop();
1513
+ }
1489
1514
  }
1490
1515
  });
1491
1516
  }
@@ -1542,7 +1567,7 @@ class RoomSession {
1542
1567
  lastSwitchTime : new Map(),
1543
1568
  }
1544
1569
 
1545
- if(this.#publisherHandle && handleId === this.#publisherHandle.handleId) {
1570
+ if(this.#publisherHandle && handleId === this.#publisherHandle?.handleId) {
1546
1571
  this.#emitLocalFeedUpdate({feedRemoval: true});
1547
1572
  }
1548
1573
  else if(this.#subscriberHandle && handleId === this.#subscriberHandle.handleId) {
@@ -1555,7 +1580,7 @@ class RoomSession {
1555
1580
  }
1556
1581
 
1557
1582
  async #joinAsPublisher(roomId, pin, userId, display) {
1558
- return this.sendMessage(this.#publisherHandle.handleId, {
1583
+ return this.sendMessage(this.#publisherHandle?.handleId, {
1559
1584
  body: {
1560
1585
  "request": "join", "room": roomId, "pin": pin, "ptype": "publisher", "display": display, ...(this.webrtcVersion > 1000 ? {id: userId} : {})
1561
1586
  }
@@ -1642,7 +1667,7 @@ class RoomSession {
1642
1667
 
1643
1668
  async #leaveRoom(dontWait = false) {
1644
1669
  return this.isConnected
1645
- ? this.sendMessage(this.#publisherHandle.handleId, {body: {"request": "leave"}}, dontWait)
1670
+ ? this.sendMessage(this.#publisherHandle?.handleId, {body: {"request": "leave"}}, dontWait)
1646
1671
  .finally(() => {
1647
1672
  this.isConnected = false;
1648
1673
  this.emit('joined', false);
@@ -1976,6 +2001,27 @@ class RoomSession {
1976
2001
  });
1977
2002
  }
1978
2003
 
2004
+ getLocalStreams() {
2005
+ const streamMap = this.#publisherHandle?.webrtcStuff?.streamMap[this.id];
2006
+ if(!streamMap) {
2007
+ return [];
2008
+ }
2009
+ return Object.keys(streamMap).reduce((acc, source) => {
2010
+ const sourceTrackIds = streamMap[source] ?? [];
2011
+ const sourceRelatedTracks = this.#publisherHandle?.webrtcStuff?.tracks?.filter(t => sourceTrackIds.includes(t.id)) ?? [];
2012
+ if(sourceRelatedTracks.length) {
2013
+ const stream = new MediaStream();
2014
+ sourceRelatedTracks.forEach(track => {
2015
+ if(track) {
2016
+ stream.addTrack(track);
2017
+ }
2018
+ });
2019
+ acc.push({source, stream});
2020
+ }
2021
+ return acc
2022
+ }, [])
2023
+ }
2024
+
1979
2025
  #enableDebug() {
1980
2026
  this._log = console.log.bind(console);
1981
2027
  }
@@ -2366,7 +2412,7 @@ class RoomSession {
2366
2412
  // removing this so we can cache ice candidates again
2367
2413
  config.remoteSdp = null;
2368
2414
 
2369
- if (this.#publisherHandle.handleId === handleId) {
2415
+ if (this.handleId === handleId) {
2370
2416
  this._log('Performing local ICE restart');
2371
2417
  let hasAudio = !!(config.stream && config.stream.getAudioTracks().length > 0);
2372
2418
  let hasVideo = !!(config.stream && config.stream.getVideoTracks().length > 0);
@@ -2515,7 +2561,7 @@ class RoomSession {
2515
2561
  .then( (response) => {
2516
2562
 
2517
2563
  // if type offer and its me and we want dtx we mungle the sdp
2518
- if(handleId === this.#publisherHandle.handleId && type === 'offer' && this.enableDtx) {
2564
+ if(handleId === this.handleId && type === 'offer' && this.enableDtx) {
2519
2565
  // enable DTX
2520
2566
  response.sdp = response.sdp.replace("useinbandfec=1", "useinbandfec=1;usedtx=1")
2521
2567
  }
@@ -2825,7 +2871,7 @@ class RoomSession {
2825
2871
  let hasAudio = !!(stream && stream.getAudioTracks().length > 0);
2826
2872
  let hasVideo = !!(stream && stream.getVideoTracks().length > 0);
2827
2873
 
2828
- this.#setupTransceivers(this.#publisherHandle.handleId, [hasAudio, false, hasVideo, false, audioTransceiver, videoTransceiver]);
2874
+ this.#setupTransceivers(this.handleId, [hasAudio, false, hasVideo, false, audioTransceiver, videoTransceiver]);
2829
2875
 
2830
2876
  const emitEvents = () => {
2831
2877
  this.isPublished = true;
@@ -2934,7 +2980,7 @@ class RoomSession {
2934
2980
 
2935
2981
  async unpublishLocal(dontWait = false) {
2936
2982
  return this.isPublished
2937
- ? this.sendMessage(this.#publisherHandle.handleId, {body: {"request": "unpublish"}}, dontWait)
2983
+ ? this.sendMessage(this.handleId, {body: {"request": "unpublish"}}, dontWait)
2938
2984
  .finally(r => {
2939
2985
  this.isPublished = false;
2940
2986
  this.emit('published', false);