@reactoo/watchtogether-sdk-js 2.5.16 → 2.5.18

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.
@@ -29,7 +29,7 @@ class Room {
29
29
  }
30
30
 
31
31
  createSession(constructId = null, type = 'reactooroom', options = {}) {
32
- return new RoomSession(constructId, type, this.debug, options);
32
+ return new RoomSession(constructId, type, {debug: this.debug, ...options});
33
33
  }
34
34
 
35
35
  static testSafariVp8() {
@@ -88,19 +88,36 @@ class RoomSession {
88
88
  //TODO: solve
89
89
  // #eventList = ['error', 'kicked', 'addLocalParticipant', ,'addRemoteInstructor','addRemoteParticipant','addRemoteTalkback', 'addRemoteObserver', 'removeRemoteInstructor', 'removeLocalParticipant', 'removeRemoteParticipant', 'removeRemoteTalkback', 'removeRemoteObserver', 'localMuted', 'localHasVideo', 'localHasAudio', 'data', 'iceState', 'connectionState', 'joined', 'joining', 'dataChannel', 'disconnect', 'observerIds', 'talkbackIds', 'instructorId', 'published', 'publishing', 'remoteTrackMuted', 'streamingStatus', 'streaming', 'streamStarting'];
90
90
  //
91
- // #sessionTypes = {
92
- // 'reactooroom': 'janus.plugin.reactooroom',
93
- // 'streaming': 'janus.plugin.streaming'
94
- // };
95
91
 
96
- static sessionTypes() {
97
- return {
98
- 'reactooroom': 'janus.plugin.reactooroom',
99
- 'streaming': 'janus.plugin.streaming'
100
- }
92
+ static sessionTypes = {
93
+ 'reactooroom': 'janus.plugin.reactooroom',
94
+ 'streaming': 'janus.plugin.streaming'
95
+ }
96
+
97
+ static subscriptionRules = {
98
+ participant: {
99
+ watchTogether: ['participant', 'talkback'],
100
+ videoWall: ['instructor', 'observer', 'talkback']
101
+ },
102
+ monitor: {
103
+ watchTogether: ['participant'],
104
+ videoWall: ['instructor', 'participant'],
105
+ },
106
+ talkback: {
107
+ watchTogether: ['participant'],
108
+ videoWall: ['instructor', 'participant'],
109
+ },
110
+ observer: {
111
+ watchTogether: ['participant'],
112
+ videoWall: ['participant'],
113
+ },
114
+ instructor: {
115
+ watchTogether: [],
116
+ videoWall: [],
117
+ },
101
118
  };
102
119
 
103
- constructor(constructId = null, type = 'reactooroom', debug, options = {}) {
120
+ constructor(constructId = null, type = 'reactooroom', options = {}) {
104
121
 
105
122
  Object.assign(this, emitter());
106
123
 
@@ -113,18 +130,11 @@ class RoomSession {
113
130
  this.userId = null;
114
131
  this.sessiontype = type;
115
132
  this.initialBitrate = 0;
133
+ //TODO: remove this
116
134
  this.isMonitor = false; // currently used just for classroom context so monitor user only subscribes to participants and not trainer (for other monitor this flag is not necessary)
117
135
  this.recordingFilename = null;
118
- this.pluginName = RoomSession.sessionTypes()[type];
119
- this.options = {
120
- ...{
121
- debug: debug,
122
- classroomObserverSubscribeToInstructor: false,
123
- classroomInstructorSubscribeToParticipants: false,
124
- safariBugHotfixEnabled: adapter.browserDetails.browser === 'safari' && adapter.browserDetails.version < 605
125
- },
126
- options
127
- };
136
+ this.pluginName = RoomSession.sessionTypes[type];
137
+ this.options = options;
128
138
  this.id = null;
129
139
  this.privateId = null;
130
140
  this.constructId = constructId || RoomSession.randomString(16);
@@ -155,10 +165,17 @@ class RoomSession {
155
165
  this.isVideoEnabled = false;
156
166
  this.isAudioEnabed = false;
157
167
  this.isUnifiedPlan = RoomSession.checkUnifiedPlan();
168
+
169
+ this.subscriptionRules = {
170
+ ...RoomSession.subscriptionRules,
171
+ ...(this.options.subscriptionRules || {})
172
+ }
173
+
158
174
  this._log = RoomSession.noop;
159
175
  if (this.options.debug) {
160
176
  this._enableDebug();
161
177
  }
178
+
162
179
  }
163
180
 
164
181
  // Check if this browser supports Unified Plan and transceivers
@@ -189,6 +206,88 @@ class RoomSession {
189
206
  }
190
207
  return unifiedPlan;
191
208
  }
209
+
210
+ _participantShouldSubscribe(userId) {
211
+ let allowedObservers = this._observerIds || [];
212
+ let allowedTalkback = this._talkbackIds || [];
213
+ let allowedInstructor = this._instuctorId || null;
214
+ let localUserRole = 'participant';
215
+ if(this.isMonitor) {
216
+ localUserRole = 'monitor';
217
+ } else if(allowedObservers.indexOf(this.userId) > -1) {
218
+ localUserRole = 'observer';
219
+ } else if(allowedTalkback.indexOf(this.userId) > -1) {
220
+ localUserRole = 'talkback';
221
+ } else if(this.userId === allowedInstructor) {
222
+ localUserRole = 'instructor';
223
+ }
224
+ let remoteUserRole = 'participant';
225
+ if(allowedObservers.indexOf(userId) > -1) {
226
+ remoteUserRole = 'observer';
227
+ } else if(allowedTalkback.indexOf(userId) > -1) {
228
+ remoteUserRole = 'talkback';
229
+ } else if(userId === allowedInstructor) {
230
+ remoteUserRole = 'instructor';
231
+ }
232
+ let mode = allowedInstructor !== null ? 'videoWall' : 'watchTogether';
233
+ return this.subscriptionRules[localUserRole][mode].indexOf(remoteUserRole) > -1;
234
+ }
235
+
236
+ _getAddParticipantEventName(handleId) {
237
+
238
+ let handle = this._getHandle(handleId);
239
+ if (!handle) {
240
+ this.emit('error', {
241
+ type: 'warning',
242
+ id: 15,
243
+ message: 'id non-existent',
244
+ data: [handleId, 'getParticipantEventName']
245
+ });
246
+ }
247
+
248
+ let allowedTalkback = this._talkbackIds || [];
249
+ let allowedObservers = this._observerIds || [];
250
+ let allowedInstructor = this._instuctorId || null;
251
+ let eventName = 'addRemoteParticipant';
252
+ if(handle.userId === allowedInstructor) {
253
+ eventName = 'addRemoteInstructor';
254
+ }
255
+ if (allowedTalkback.indexOf(handle.userId) > -1) {
256
+ eventName = 'addRemoteTalkback';
257
+ }
258
+ if (allowedObservers.indexOf(handle.userId) > -1) {
259
+ eventName = 'addRemoteObserver';
260
+ }
261
+ return eventName
262
+ }
263
+
264
+ _getRemoveParticipantEventName(handleId) {
265
+
266
+ let handle = this._getHandle(handleId);
267
+ if (!handle) {
268
+ this.emit('error', {
269
+ type: 'warning',
270
+ id: 15,
271
+ message: 'id non-existent',
272
+ data: [handleId, 'getParticipantEventName']
273
+ });
274
+ }
275
+
276
+ let allowedTalkback = this._talkbackIds || [];
277
+ let allowedObservers = this._observerIds || [];
278
+ let allowedInstructor = this._instuctorId || null;
279
+ let eventName = 'removeRemoteParticipant';
280
+ if(handle.userId === allowedInstructor) {
281
+ eventName = 'removeRemoteInstructor';
282
+ }
283
+ if (allowedTalkback.indexOf(handle.userId) > -1) {
284
+ eventName = 'removeRemoteTalkback';
285
+ }
286
+ if (allowedObservers.indexOf(handle.userId) > -1) {
287
+ eventName = 'removeRemoteObserver';
288
+ }
289
+ return eventName
290
+ }
192
291
 
193
292
  sendMessage(handleId, message = {body: 'Example Body'}, dontWait = false, dontResolveOnAck = false) {
194
293
  return this._send({
@@ -280,7 +379,7 @@ class RoomSession {
280
379
  this.stopStream();
281
380
  }
282
381
 
283
- this.emit('error', {type: 'error', id: 4, message: 'lost connection to WebSockets', data: null});
382
+ this.emit('error', {type: 'error', id: 4, message: 'Lost connection to WebSockets', data: null});
284
383
  }
285
384
  }
286
385
 
@@ -316,7 +415,7 @@ class RoomSession {
316
415
  _stopKeepAlive() {
317
416
  clearTimeout(this._keepAliveId);
318
417
  }
319
-
418
+
320
419
  _handleWsEvents(event) {
321
420
 
322
421
  let json = JSON.parse(event.data);
@@ -401,68 +500,7 @@ class RoomSession {
401
500
  streams[i]["display"] = userId;
402
501
  }
403
502
  this._log('Remote userId: ', userId);
404
-
405
- let isClassroom = allowedInstructor !== null;
406
- let subscribeCondition;
407
- let subCondition = false
408
-
409
- if(!isClassroom) {
410
- subscribeCondition = allowedObservers.indexOf(userId) === -1 && allowedTalkback.indexOf(this.userId) === -1;
411
- } else {
412
-
413
- // instructor -> everyone but observer
414
- if(this.options.classroomInstructorSubscribeToParticipants) {
415
- subCondition = this.userId === allowedInstructor && allowedObservers.indexOf(userId) === -1;
416
- }
417
-
418
- if(this.options.classroomObserverSubscribeToInstructor) {
419
-
420
- /*
421
-
422
- monitor/talkback -> all but talkback
423
- observer -> all but talkback
424
- instructor -> no one
425
- participant -> only instructor, observer and talkback
426
-
427
- 1st line -> Im not monitor/talkback and im not observer and im not instructor and user to subscribe is instructor or observer or talkback
428
- 2nd line -> Im monitor/talkback and im not instructor and user connecting is not talkback
429
- 3rd line -> Im observer and im not instructor and user connecting is not talkback
430
-
431
- */
432
-
433
- subscribeCondition = subCondition ||
434
- ((!this.isMonitor && allowedObservers.indexOf(this.userId) === -1 && this.userId !== allowedInstructor) && (userId === allowedInstructor || allowedObservers.indexOf(userId) > -1 || allowedTalkback.indexOf(userId) > -1)) ||
435
- (this.isMonitor && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1) ||
436
- (allowedObservers.indexOf(this.userId) > -1 && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1)
437
-
438
-
439
-
440
- } else {
441
-
442
- /*
443
-
444
- monitor/talkback -> all but talkback
445
- observer -> all but instructor and talkback
446
- instructor -> no one
447
- participant -> only instructor, observer and talkback
448
-
449
- 1st line -> Im not monitor/talkback and im not observer and im not instructor and user to subscribe is instructor or observer or talkback
450
- 2nd line -> Im monitor/talkback and im not instructor and user connecting is not talkback
451
- 3rd line -> Im observer and im not instructor and user connecting is not instructor and its not talkback
452
-
453
- */
454
-
455
- subscribeCondition = subCondition ||
456
- ((!this.isMonitor && allowedObservers.indexOf(this.userId) === -1 && this.userId !== allowedInstructor) && (userId === allowedInstructor || allowedObservers.indexOf(userId) > -1 || allowedTalkback.indexOf(userId) > -1)) ||
457
- (this.isMonitor && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1) ||
458
- (allowedObservers.indexOf(this.userId) > -1 && this.userId !== allowedInstructor && userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1)
459
-
460
- }
461
-
462
-
463
- }
464
-
465
- if (subscribeCondition) {
503
+ if (this._participantShouldSubscribe(userId)) {
466
504
  this._log('Creating user: ', userId);
467
505
  this._createParticipant(userId, id)
468
506
  .then(handle => {
@@ -497,66 +535,7 @@ class RoomSession {
497
535
  streams[i]["display"] = userId;
498
536
  }
499
537
  this._log('Remote userId: ', userId);
500
-
501
- let isClassroom = allowedInstructor !== null;
502
- let subscribeCondition;
503
- let subCondition = false
504
-
505
- if(!isClassroom) {
506
- subscribeCondition = allowedObservers.indexOf(userId) === -1 && allowedTalkback.indexOf(this.userId) === -1;
507
- } else {
508
-
509
- // instructor -> everyone but observer
510
- if(this.options.classroomInstructorSubscribeToParticipants) {
511
- subCondition = this.userId === allowedInstructor && allowedObservers.indexOf(userId) === -1;
512
- }
513
-
514
- if(this.options.classroomObserverSubscribeToInstructor) {
515
-
516
- /*
517
-
518
- monitor/talkback -> all but talkback
519
- observer -> all but talkback
520
- instructor -> no one
521
- participant -> only instructor, observer and talkback
522
-
523
- 1st line -> Im not monitor/talkback and im not observer and im not instructor and user to subscribe is instructor or observer or talkback
524
- 2nd line -> Im monitor/talkback and im not instructor and user connecting is not talkback
525
- 3rd line -> Im observer and im not instructor and user connecting is not talkback
526
-
527
- */
528
-
529
- subscribeCondition = subCondition ||
530
- ((!this.isMonitor && allowedObservers.indexOf(this.userId) === -1 && this.userId !== allowedInstructor) && (userId === allowedInstructor || allowedObservers.indexOf(userId) > -1 || allowedTalkback.indexOf(userId) > -1)) ||
531
- (this.isMonitor && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1) ||
532
- (allowedObservers.indexOf(this.userId) > -1 && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1)
533
-
534
-
535
-
536
- } else {
537
-
538
- /*
539
-
540
- monitor/talkback -> all but talkback
541
- observer -> all but instructor and talkback
542
- instructor -> no one
543
- participant -> only instructor, observer and talkback
544
-
545
- 1st line -> Im not monitor/talkback and im not observer and im not instructor and user to subscribe is instructor or observer or talkback
546
- 2nd line -> Im monitor/talkback and im not instructor and user connecting is not talkback
547
- 3rd line -> Im observer and im not instructor and user connecting is not instructor and its not talkback
548
-
549
- */
550
-
551
- subscribeCondition = subCondition ||
552
- ((!this.isMonitor && allowedObservers.indexOf(this.userId) === -1 && this.userId !== allowedInstructor) && (userId === allowedInstructor || allowedObservers.indexOf(userId) > -1 || allowedTalkback.indexOf(userId) > -1)) ||
553
- (this.isMonitor && this.userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1) ||
554
- (allowedObservers.indexOf(this.userId) > -1 && this.userId !== allowedInstructor && userId !== allowedInstructor && allowedTalkback.indexOf(userId) === -1)
555
-
556
- }
557
- }
558
-
559
- if (subscribeCondition) {
538
+ if (this._participantShouldSubscribe(userId)) {
560
539
  this._log('Creating user: ', userId);
561
540
  this._createParticipant(userId, id)
562
541
  .then(handle => {
@@ -660,16 +639,7 @@ class RoomSession {
660
639
 
661
640
  if (event === "attached") {
662
641
  this._log('Remote have successfully joined Room', msg);
663
- let allowedTalkback = this._talkbackIds || [];
664
- let allowedObservers = this._observerIds || [];
665
- let eventName = 'addRemoteParticipant';
666
- if (allowedTalkback.indexOf(handle.userId) > -1) {
667
- eventName = 'addRemoteTalkback';
668
- }
669
- if (allowedObservers.indexOf(handle.userId) > -1) {
670
- eventName = 'addRemoteObserver';
671
- }
672
- this.emit(eventName, {
642
+ this.emit(this._getAddParticipantEventName(handle.handleId), {
673
643
  tid: generateUUID(),
674
644
  id: handle.handleId,
675
645
  userId: handle.userId,
@@ -807,20 +777,7 @@ class RoomSession {
807
777
  this.emit('published', {status: false, hasStream: false});
808
778
  this.emit('removeLocalParticipant', {id: handleId, userId: handle.userId});
809
779
  } else {
810
- let allowedTalkback = this._talkbackIds || [];
811
- let allowedObservers = this._observerIds || [];
812
- let allowedInstructor = this._instuctorId || null;
813
- let eventName = 'removeRemoteParticipant';
814
- if(handle.userId === allowedInstructor) {
815
- eventName = 'removeRemoteInstructor';
816
- }
817
- if (allowedTalkback.indexOf(handle.userId) > -1) {
818
- eventName = 'removeRemoteTalkback';
819
- }
820
- if (allowedObservers.indexOf(handle.userId) > -1) {
821
- eventName = 'removeRemoteObserver';
822
- }
823
- this.emit(eventName, {id: handleId, userId: handle.userId});
780
+ this.emit(this._getRemoveParticipantEventName(handleId), {id: handleId, userId: handle.userId});
824
781
  }
825
782
 
826
783
  if (removeHandle) {
@@ -1134,7 +1091,7 @@ class RoomSession {
1134
1091
  _enableDebug() {
1135
1092
  this._log = console.log.bind(console);
1136
1093
  }
1137
-
1094
+
1138
1095
  _getHandle(handleId, rfid = null) {
1139
1096
  return this._participants.find(p => p.handleId === handleId || (rfid && p.rfid === rfid));
1140
1097
  }
@@ -1198,12 +1155,40 @@ class RoomSession {
1198
1155
  this._iceRestart(handleId);
1199
1156
  }
1200
1157
  this.emit('connectionState', [handleId, handleId === this.handleId, config.pc.connectionState]);
1158
+ if(handleId !== this.handleId && config.pc.connectionState === 'connected') {
1159
+ this.emit(this._getAddParticipantEventName(handle.handleId), {
1160
+ tid: generateUUID(),
1161
+ id: handle.handleId,
1162
+ userId: handle.userId,
1163
+ stream: config.stream,
1164
+ optional: true,
1165
+ constructId: this.constructId,
1166
+ metaData: this.options.metaData,
1167
+ adding: true,
1168
+ hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),
1169
+ hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)
1170
+ })
1171
+ }
1201
1172
  };
1202
1173
  config.pc.oniceconnectionstatechange = () => {
1203
1174
  if (config.pc.iceConnectionState === 'failed') {
1204
1175
  this._iceRestart(handleId);
1205
1176
  }
1206
1177
  this.emit('iceState', [handleId, handleId === this.handleId, config.pc.iceConnectionState]);
1178
+ if(handleId !== this.handleId && (config.pc.iceConnectionState === 'completed' || config.pc.iceConnectionState === 'connected')) {
1179
+ this.emit(this._getAddParticipantEventName(handle.handleId), {
1180
+ tid: generateUUID(),
1181
+ id: handle.handleId,
1182
+ userId: handle.userId,
1183
+ stream: config.stream,
1184
+ optional: true,
1185
+ constructId: this.constructId,
1186
+ metaData: this.options.metaData,
1187
+ adding: true,
1188
+ hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),
1189
+ hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)
1190
+ })
1191
+ }
1207
1192
  };
1208
1193
  config.pc.onicecandidate = (event) => {
1209
1194
  if (event.candidate == null || (adapter.browserDetails.browser === 'edge' && event.candidate.candidate.indexOf('endOfCandidates') > 0)) {
@@ -1241,26 +1226,8 @@ class RoomSession {
1241
1226
  }
1242
1227
 
1243
1228
  if (event.track) {
1244
-
1245
1229
  config.stream.addTrack(event.track);
1246
-
1247
- let allowedTalkback = this._talkbackIds || [];
1248
- let allowedObservers = this._observerIds || [];
1249
- let allowedInstructor = this._instuctorId || null;
1250
- let eventName = 'addRemoteParticipant';
1251
- if(handle.userId === allowedInstructor) {
1252
- eventName = 'addRemoteInstructor';
1253
- }
1254
- if (allowedTalkback.indexOf(handle.userId) > -1) {
1255
- eventName = 'addRemoteTalkback';
1256
- }
1257
- if (allowedObservers.indexOf(handle.userId) > -1) {
1258
- eventName = 'addRemoteObserver';
1259
- }
1260
-
1261
- this._log(eventName, 'ontrack');
1262
-
1263
- this.emit(eventName, {
1230
+ this.emit(this._getAddParticipantEventName(handle.handleId), {
1264
1231
  tid: generateUUID(),
1265
1232
  id: handle.handleId,
1266
1233
  userId: handle.userId,
@@ -1277,25 +1244,9 @@ class RoomSession {
1277
1244
  return;
1278
1245
 
1279
1246
  event.track.onended = (ev) => {
1280
-
1281
- let allowedTalkback = this._talkbackIds || [];
1282
- let allowedObservers = this._observerIds || [];
1283
- let allowedInstructor = this._instuctorId || null;
1284
- let eventName = 'addRemoteParticipant';
1285
- if(handle.userId === allowedInstructor) {
1286
- eventName = 'addRemoteInstructor';
1287
- }
1288
- if (allowedTalkback.indexOf(handle.userId) > -1) {
1289
- eventName = 'addRemoteTalkback';
1290
- }
1291
- if (allowedObservers.indexOf(handle.userId) > -1) {
1292
- eventName = 'addRemoteObserver';
1293
- }
1294
-
1295
- this._log(eventName, 'onended');
1296
1247
  if (config.stream) {
1297
1248
  config.stream && config.stream.removeTrack(ev.target);
1298
- this.emit(eventName, {
1249
+ this.emit(this._getAddParticipantEventName(handle.handleId), {
1299
1250
  tid: generateUUID(),
1300
1251
  id: handle.handleId,
1301
1252
  userId: handle.userId,
@@ -1371,7 +1322,7 @@ class RoomSession {
1371
1322
 
1372
1323
  let handle = this._getHandle(handleId);
1373
1324
  if (!handle) {
1374
- return Promise.reject({type: 'warning', id: 16, message: 'id non-existent', data: [handleId, 'rtc peer']});
1325
+ return Promise.reject({type: 'warning', id: 15, message: 'id non-existent', data: [handleId, 'rtc peer']});
1375
1326
  }
1376
1327
 
1377
1328
  var config = handle.webrtcStuff;
@@ -1461,7 +1412,7 @@ class RoomSession {
1461
1412
  if (!handle) {
1462
1413
  return Promise.reject({
1463
1414
  type: 'warning',
1464
- id: 17,
1415
+ id: 15,
1465
1416
  message: 'id non-existent',
1466
1417
  data: [handleId, 'createAO', type]
1467
1418
  });
@@ -1638,7 +1589,7 @@ class RoomSession {
1638
1589
  if (!handle) {
1639
1590
  return Promise.reject({
1640
1591
  type: 'warning',
1641
- id: 18,
1592
+ id: 15,
1642
1593
  message: 'id non-existent',
1643
1594
  data: [handleId, 'publish remote participant']
1644
1595
  })
@@ -1936,10 +1887,7 @@ class RoomSession {
1936
1887
  }
1937
1888
  let config = handle.webrtcStuff;
1938
1889
 
1939
- if(this.options.safariBugHotfixEnabled) {
1940
- this.isVideoMuted = !this.isVideoMuted;
1941
- }
1942
- else if (this.isUnifiedPlan) {
1890
+ if (this.isUnifiedPlan) {
1943
1891
  let transceiver = config.pc.getTransceivers()
1944
1892
  .find(t => t.sender && t.sender.track && t.receiver.track.kind === "video" && t.stopped === false);
1945
1893
  if (transceiver) {