@reactoo/watchtogether-sdk-js 2.5.21 → 2.5.24

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.
@@ -5,7 +5,7 @@ import emitter from './wt-emitter';
5
5
  import {generateUUID} from "./wt-utils";
6
6
 
7
7
  class Room {
8
-
8
+
9
9
  constructor(debug) {
10
10
  this.debug = debug;
11
11
  this.sessions = [];
@@ -22,16 +22,16 @@ class Room {
22
22
  // Let's get it started
23
23
  this.whenInitialized = this.initialize();
24
24
  }
25
-
25
+
26
26
  initialize() {
27
27
  return this.safariVp8TestPromise
28
28
  .then(() => this);
29
29
  }
30
-
30
+
31
31
  createSession(constructId = null, type = 'reactooroom', options = {}) {
32
32
  return new RoomSession(constructId, type, {debug: this.debug, ...options});
33
33
  }
34
-
34
+
35
35
  static testSafariVp8() {
36
36
  return new Promise(resolve => {
37
37
  if (adapter.browserDetails.browser === 'safari' &&
@@ -61,7 +61,7 @@ class Room {
61
61
  } else resolve(false);
62
62
  });
63
63
  }
64
-
64
+
65
65
  static isWebrtcSupported() {
66
66
  return window.RTCPeerConnection !== undefined && window.RTCPeerConnection !== null &&
67
67
  navigator.mediaDevices !== undefined && navigator.mediaDevices !== null &&
@@ -70,9 +70,9 @@ class Room {
70
70
  }
71
71
 
72
72
  class RoomSession {
73
-
73
+
74
74
  static noop() {
75
-
75
+
76
76
  }
77
77
 
78
78
  static randomString(len) {
@@ -84,11 +84,11 @@ class RoomSession {
84
84
  }
85
85
  return randomString;
86
86
  }
87
-
87
+
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
-
91
+
92
92
  static sessionTypes = {
93
93
  'reactooroom': 'janus.plugin.reactooroom',
94
94
  'streaming': 'janus.plugin.streaming'
@@ -116,11 +116,11 @@ class RoomSession {
116
116
  videoWall: [],
117
117
  },
118
118
  };
119
-
119
+
120
120
  constructor(constructId = null, type = 'reactooroom', options = {}) {
121
121
 
122
122
  Object.assign(this, emitter());
123
-
123
+ this.defaultDataChannelLabel = 'JanusDataChannel'
124
124
  this.server = null;
125
125
  this.iceServers = null;
126
126
  this.token = null;
@@ -147,7 +147,7 @@ class RoomSession {
147
147
  // double click prevention
148
148
  this.connectingPromise = null;
149
149
  this.disconnectingPromise = null;
150
-
150
+
151
151
  this._ipv6Support = false;
152
152
  this._retries = 0;
153
153
  this._maxRetries = 3;
@@ -160,6 +160,8 @@ class RoomSession {
160
160
  this._isStreaming = false;
161
161
  this._isPublished = false;
162
162
  this._isDataChannelOpen = false;
163
+ this._dataChannelTimeoutId = null;
164
+ this._messageTimeoutId = null;
163
165
  this.isAudioMuted = false;
164
166
  this.isVideoMuted = false;
165
167
  this.isVideoEnabled = false;
@@ -177,7 +179,7 @@ class RoomSession {
177
179
  }
178
180
 
179
181
  }
180
-
182
+
181
183
  // Check if this browser supports Unified Plan and transceivers
182
184
  // Based on https://codepen.io/anon/pen/ZqLwWV?editors=0010
183
185
  static checkUnifiedPlan() {
@@ -288,7 +290,7 @@ class RoomSession {
288
290
  }
289
291
  return eventName
290
292
  }
291
-
293
+
292
294
  sendMessage(handleId, message = {body: 'Example Body'}, dontWait = false, dontResolveOnAck = false) {
293
295
  return this._send({
294
296
  "janus": "message",
@@ -311,7 +313,7 @@ class RoomSession {
311
313
  }
312
314
  })
313
315
  }
314
-
316
+
315
317
  _send(request = {}, ignoreResponse = false, dontResolveOnAck = false) {
316
318
  let transaction = RoomSession.randomString(12);
317
319
  let requestData = {
@@ -319,14 +321,12 @@ class RoomSession {
319
321
  transaction,
320
322
  token: this.token, ...((this.sessionId && {'session_id': this.sessionId}) || {})
321
323
  };
322
- let timeouId = null;
323
-
324
324
  return new Promise((resolve, reject) => {
325
325
  let parseResponse = (event) => {
326
326
  let json = JSON.parse(event.data);
327
327
  let r_transaction = json['transaction'];
328
328
  if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {
329
- clearTimeout(timeouId);
329
+ clearTimeout(this._messageTimeoutId);
330
330
  this.ws.removeEventListener('message', parseResponse);
331
331
  if (json['janus'] === 'error') {
332
332
  if (json?.error?.code == 403) {
@@ -338,17 +338,17 @@ class RoomSession {
338
338
  }
339
339
  }
340
340
  };
341
-
341
+
342
342
  if (ignoreResponse) {
343
343
  if (this.ws && this.ws.readyState === 1) {
344
344
  this.ws.send(JSON.stringify(requestData));
345
345
  }
346
346
  resolve();
347
-
347
+
348
348
  } else {
349
349
  if (this.ws && this.ws.readyState === 1) {
350
350
  this.ws.addEventListener('message', parseResponse);
351
- timeouId = setTimeout(() => {
351
+ this._messageTimeoutId = setTimeout(() => {
352
352
  this.ws.removeEventListener('message', parseResponse);
353
353
  reject({type: 'error', id: 3, message: 'send timeout', data: requestData});
354
354
  }, 10000);
@@ -359,12 +359,12 @@ class RoomSession {
359
359
  }
360
360
  })
361
361
  }
362
-
362
+
363
363
  _connectionClosed() {
364
364
  if (this.disconnectingPromise || this.connectingPromise) {
365
365
  return;
366
366
  }
367
-
367
+
368
368
  if (this._retries < this._maxRetries) {
369
369
  setTimeout(() => {
370
370
  this._retries++;
@@ -378,18 +378,18 @@ class RoomSession {
378
378
  } else if (this.sessiontype === 'streaming') {
379
379
  this.stopStream();
380
380
  }
381
-
381
+
382
382
  this.emit('error', {type: 'error', id: 4, message: 'Lost connection to WebSockets', data: null});
383
383
  }
384
384
  }
385
-
385
+
386
386
  _wipeListeners() {
387
387
  if (this.ws) {
388
388
  this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
389
389
  this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
390
390
  }
391
391
  }
392
-
392
+
393
393
  _startKeepAlive() {
394
394
  this._send({"janus": "keepalive"})
395
395
  .then(json => {
@@ -406,27 +406,27 @@ class RoomSession {
406
406
  this.emit('error', {type: 'warning', id: 6, message: 'keepalive dead', data: e});
407
407
  this._connectionClosed();
408
408
  });
409
-
409
+
410
410
  this._keepAliveId = setTimeout(() => {
411
411
  this._startKeepAlive();
412
412
  }, 30000);
413
413
  }
414
-
414
+
415
415
  _stopKeepAlive() {
416
416
  clearTimeout(this._keepAliveId);
417
417
  }
418
418
 
419
419
  _handleWsEvents(event) {
420
-
420
+
421
421
  let json = JSON.parse(event.data);
422
422
  var sender = json["sender"];
423
423
  var type = json["janus"];
424
-
424
+
425
425
  let handle = this._getHandle(sender);
426
426
  if (!handle) {
427
427
  return;
428
428
  }
429
-
429
+
430
430
  if (type === "trickle") {
431
431
  let candidate = json["candidate"];
432
432
  let config = handle.webrtcStuff;
@@ -463,16 +463,16 @@ class RoomSession {
463
463
  } else {
464
464
  this._log(`Unknown event: ${type} on session: ${this.sessionId}`);
465
465
  }
466
-
467
-
466
+
467
+
468
468
  // LOCAL
469
-
469
+
470
470
  if (sender === this.handleId) {
471
471
  if (type === "event") {
472
472
  var plugindata = json["plugindata"] || {};
473
473
  var msg = plugindata["data"] || {};
474
474
  var jsep = json["jsep"];
475
-
475
+
476
476
  let result = msg["result"] || null;
477
477
  let event = msg["videoroom"] || null;
478
478
  let list = msg["publishers"] || {};
@@ -480,7 +480,7 @@ class RoomSession {
480
480
  //let joining = msg["joining"];
481
481
  let unpublished = msg["unpublished"];
482
482
  let error = msg["error"];
483
-
483
+
484
484
  if (event === "joined") {
485
485
  this.id = msg["id"];
486
486
  this.privateId = msg["private_id"];
@@ -517,11 +517,11 @@ class RoomSession {
517
517
  }
518
518
  }
519
519
  } else if (event === "event") {
520
-
520
+
521
521
  if (msg["streams"] !== undefined && msg["streams"] !== null) {
522
522
  this._log('Got my own streams back', msg["streams"]);
523
523
  }
524
-
524
+
525
525
  for (let f in list) {
526
526
  let userId = list[f]["display"];
527
527
  let streams = list[f]["streams"] || [];
@@ -551,7 +551,7 @@ class RoomSession {
551
551
  })
552
552
  }
553
553
  }
554
-
554
+
555
555
  if (leaving === 'ok') {
556
556
  this._log('leaving', this.handleId, 'this is us');
557
557
  this._removeParticipant(this.handleId);
@@ -564,7 +564,7 @@ class RoomSession {
564
564
  this._log('leaving', leaving);
565
565
  this._removeParticipant(null, leaving);
566
566
  }
567
-
567
+
568
568
  if (unpublished === 'ok') {
569
569
  this._log('unpublished', this.handleId, 'this is us');
570
570
  this._removeParticipant(this.handleId, null, false); // we do just hangup
@@ -572,7 +572,7 @@ class RoomSession {
572
572
  this._log('unpublished', unpublished);
573
573
  this._removeParticipant(null, unpublished, true); // we do hangup and detach
574
574
  }
575
-
575
+
576
576
  if (error) {
577
577
  this.emit('error', {
578
578
  type: 'error',
@@ -582,7 +582,7 @@ class RoomSession {
582
582
  });
583
583
  }
584
584
  }
585
-
585
+
586
586
  // Streaming related
587
587
  else if (result && result["status"]) {
588
588
  this.emit('streamingStatus', result["status"]);
@@ -594,9 +594,9 @@ class RoomSession {
594
594
  this._isStreaming = true;
595
595
  }
596
596
  }
597
-
597
+
598
598
  if (jsep !== undefined && jsep !== null) {
599
-
599
+
600
600
  if (this.sessiontype === 'reactooroom') {
601
601
  this._webrtcPeer(this.handleId, jsep)
602
602
  .catch(err => {
@@ -608,7 +608,7 @@ class RoomSession {
608
608
  this.emit('error', err);
609
609
  });
610
610
  }
611
-
611
+
612
612
  }
613
613
  } else if (type === "webrtcup") {
614
614
  this._log('Configuring bitrate: ' + this.initialBitrate);
@@ -622,17 +622,17 @@ class RoomSession {
622
622
  }
623
623
  }
624
624
  }
625
-
625
+
626
626
  //REMOTE
627
-
627
+
628
628
  else {
629
-
629
+
630
630
  let plugindata = json["plugindata"] || {};
631
631
  let msg = plugindata["data"] || {};
632
632
  let jsep = json["jsep"];
633
633
  let event = msg["videoroom"];
634
634
  let error = msg["error"];
635
-
635
+
636
636
  if (event === "attached") {
637
637
  this._log('Remote have successfully joined Room', msg);
638
638
  this.emit(this._getAddParticipantEventName(handle.handleId), {
@@ -648,11 +648,11 @@ class RoomSession {
648
648
  hasVideoTrack: false
649
649
  });
650
650
  }
651
-
651
+
652
652
  if (error) {
653
653
  this.emit('error', {type: 'warning', id: 8, message: 'remote participant error', data: [sender, msg]});
654
654
  }
655
-
655
+
656
656
  if (jsep) {
657
657
  this._publishRemote(handle.handleId, jsep)
658
658
  .catch(err => {
@@ -661,24 +661,24 @@ class RoomSession {
661
661
  }
662
662
  }
663
663
  }
664
-
664
+
665
665
  _handleDataEvents(handleId, type, data) {
666
-
666
+
667
667
  let handle = this._getHandle(handleId);
668
-
668
+
669
669
  if (type === 'state') {
670
- this._log(` - Data channel status - `, `UID: ${handleId}`, `STATUS: ${data}`, `ME: ${handleId === this.handleId}`)
670
+ this._log(` - Data channel status - `, `UID: ${handleId}`, `STATUS: ${JSON.stringify(data)}`, `ME: ${handleId === this.handleId}`)
671
671
  if (handle) {
672
672
  let config = handle.webrtcStuff;
673
- config.dataChannelOpen = data === 'open';
673
+ config.dataChannelOpen = this.defaultDataChannelLabel === data?.label && data?.state === 'open';
674
674
  }
675
-
676
- if (handleId === this.handleId) {
677
- this._isDataChannelOpen = data === 'open';
678
- this.emit('dataChannel', data === 'open');
675
+
676
+ if (handleId === this.handleId && this.defaultDataChannelLabel === data?.label) {
677
+ this._isDataChannelOpen = data?.state === 'open';
678
+ this.emit('dataChannel', data?.state === 'open');
679
679
  }
680
680
  }
681
-
681
+
682
682
  if (type === 'error') {
683
683
 
684
684
  this.emit('error', {
@@ -687,21 +687,23 @@ class RoomSession {
687
687
  message: 'data event warning',
688
688
  data: [handleId, data]
689
689
  });
690
-
690
+
691
691
  if (handle) {
692
692
  let config = handle.webrtcStuff;
693
- config.dataChannelOpen = false;
693
+ if(this.defaultDataChannelLabel === data.label) {
694
+ config.dataChannelOpen = false;
695
+ }
694
696
  }
695
- if (handleId === this.handleId) {
697
+ if (handleId === this.handleId && this.defaultDataChannelLabel === data.label) {
696
698
  this._isDataChannelOpen = false;
697
699
  this.emit('dataChannel', false);
698
700
  }
699
701
  }
700
-
702
+
701
703
  if (handleId === this.handleId && type === 'message') {
702
-
704
+
703
705
  let d = null;
704
-
706
+
705
707
  try {
706
708
  d = JSON.parse(data)
707
709
  } catch (e) {
@@ -710,19 +712,19 @@ class RoomSession {
710
712
  }
711
713
  this.emit('data', d);
712
714
  }
713
-
715
+
714
716
  }
715
-
717
+
716
718
  //removeHandle === true -> hangup, detach, removeHandle === false -> hangup
717
719
  _removeParticipant(handleId, rfid, removeHandle = true) {
718
720
  let handle = this._getHandle(handleId, rfid);
719
-
721
+
720
722
  if (!handle) {
721
723
  return Promise.resolve();
722
724
  } else {
723
725
  handleId = handle.handleId;
724
726
  }
725
-
727
+
726
728
  return this._send({"janus": "hangup", "handle_id": handleId,}, true)
727
729
  .then(() => (removeHandle ? this._send({
728
730
  "janus": "detach",
@@ -738,10 +740,12 @@ class RoomSession {
738
740
  }
739
741
  handle.webrtcStuff.stream = null;
740
742
  if (handle.webrtcStuff.dataChannel) {
741
- handle.webrtcStuff.dataChannel.onmessage = null;
742
- handle.webrtcStuff.dataChannel.onopen = null;
743
- handle.webrtcStuff.dataChannel.onclose = null;
744
- handle.webrtcStuff.dataChannel.onerror = null;
743
+ Object.keys(handle.webrtcStuff.dataChannel).forEach(label => {
744
+ handle.webrtcStuff.dataChannel[label].onmessage = null;
745
+ handle.webrtcStuff.dataChannel[label].onopen = null;
746
+ handle.webrtcStuff.dataChannel[label].onclose = null;
747
+ handle.webrtcStuff.dataChannel[label].onerror = null;
748
+ })
745
749
  }
746
750
  if (handle.webrtcStuff.pc) {
747
751
  handle.webrtcStuff.pc.onicecandidate = null;
@@ -766,7 +770,7 @@ class RoomSession {
766
770
  trickle: true,
767
771
  iceDone: false,
768
772
  };
769
-
773
+
770
774
  if (handleId === this.handleId) {
771
775
  this._isDataChannelOpen = false;
772
776
  this._isPublished = false;
@@ -780,12 +784,12 @@ class RoomSession {
780
784
  let handleIndex = this._participants.findIndex(p => p.handleId === handleId);
781
785
  this._participants.splice(handleIndex, 1);
782
786
  }
783
-
787
+
784
788
  return true;
785
789
  });
786
-
790
+
787
791
  }
788
-
792
+
789
793
  _createParticipant(userId = null, rfid = null) {
790
794
  return this._send({
791
795
  "janus": "attach",
@@ -812,7 +816,7 @@ class RoomSession {
812
816
  return handle;
813
817
  })
814
818
  }
815
-
819
+
816
820
  _joinRoom(roomId, pin, userId) {
817
821
  return this.sendMessage(this.handleId, {
818
822
  body: {
@@ -820,7 +824,7 @@ class RoomSession {
820
824
  }
821
825
  }, false, true)
822
826
  }
823
-
827
+
824
828
  _watchStream(id) {
825
829
  return this.sendMessage(this.handleId, {
826
830
  body: {
@@ -828,7 +832,7 @@ class RoomSession {
828
832
  }
829
833
  }, false, true)
830
834
  }
831
-
835
+
832
836
  _leaveRoom(dontWait = false) {
833
837
  return this._hasJoined
834
838
  ? this.sendMessage(this.handleId, {body: {"request": "leave"}}, dontWait)
@@ -838,15 +842,15 @@ class RoomSession {
838
842
  })
839
843
  : Promise.resolve();
840
844
  }
841
-
845
+
842
846
  // internal reconnect
843
-
847
+
844
848
  _reconnect() {
845
-
849
+
846
850
  if (this.connectingPromise) {
847
851
  return this.connectingPromise;
848
852
  }
849
-
853
+
850
854
  if (this.ws) {
851
855
  this._wipeListeners();
852
856
  if (this.ws.readyState === 1) {
@@ -877,7 +881,7 @@ class RoomSession {
877
881
  reject({type: 'error', id: 11, message: 'reconnection error', data: error})
878
882
  });
879
883
  };
880
-
884
+
881
885
  // this is called before 'close' event callback so it doesn't break reconnect loop
882
886
  this.ws.onerror = (e) => {
883
887
  this.connectingPromise = null;
@@ -887,13 +891,13 @@ class RoomSession {
887
891
  });
888
892
  return this.connectingPromise;
889
893
  }
890
-
894
+
891
895
  connect(roomId, pin, server, iceServers, token, userId, webrtcVersion = 0, initialBitrate = 0, isMonitor, recordingFilename) {
892
-
896
+
893
897
  if (this.connectingPromise) {
894
898
  return this.connectingPromise;
895
899
  }
896
-
900
+
897
901
  this.emit('joined', false);
898
902
  if (this.ws) {
899
903
  this._wipeListeners();
@@ -951,12 +955,13 @@ class RoomSession {
951
955
  });
952
956
  return this.connectingPromise;
953
957
  }
954
-
958
+
955
959
  disconnect() {
956
960
  if (this.disconnectingPromise) {
957
961
  return this.disconnectingPromise;
958
962
  }
959
-
963
+ clearTimeout(this._messageTimeoutId);
964
+ clearTimeout(this._dataChannelTimeoutId);
960
965
  this._stopKeepAlive();
961
966
  this.disconnectingPromise = Promise.all(this._participants.map(p => this._removeParticipant(p.handleId)))
962
967
  .finally(() => {
@@ -976,13 +981,13 @@ class RoomSession {
976
981
  })
977
982
  return this.disconnectingPromise;
978
983
  }
979
-
984
+
980
985
  startStream(streamId, server, iceServers, token, userId) {
981
-
986
+
982
987
  if (this.connectingPromise) {
983
988
  return this.connectingPromise
984
989
  }
985
-
990
+
986
991
  this.emit('streaming', false);
987
992
  if (this.ws) {
988
993
  this._wipeListeners();
@@ -995,7 +1000,7 @@ class RoomSession {
995
1000
  this.token = token;
996
1001
  this.streamId = streamId;
997
1002
  this.userId = userId;
998
-
1003
+
999
1004
  this.connectingPromise = new Promise((resolve, reject) => {
1000
1005
  this.emit('streamStarting', true);
1001
1006
  this.ws = new WebSocket(this.server, 'janus-protocol');
@@ -1036,7 +1041,7 @@ class RoomSession {
1036
1041
  });
1037
1042
  return this.connectingPromise;
1038
1043
  }
1039
-
1044
+
1040
1045
  stopStream() {
1041
1046
  if (this.disconnectingPromise) {
1042
1047
  return this.disconnectingPromise;
@@ -1062,13 +1067,13 @@ class RoomSession {
1062
1067
  this.disconnectingPromise = null;
1063
1068
  return Promise.resolve('Disconnected');
1064
1069
  });
1065
-
1070
+
1066
1071
  return this.disconnectingPromise;
1067
1072
  }
1068
-
1069
-
1073
+
1074
+
1070
1075
  destroy() {
1071
-
1076
+
1072
1077
  if (this.sessiontype === 'reactooroom') {
1073
1078
  return this.disconnect()
1074
1079
  .then(() => {
@@ -1083,7 +1088,7 @@ class RoomSession {
1083
1088
  })
1084
1089
  }
1085
1090
  }
1086
-
1091
+
1087
1092
  _enableDebug() {
1088
1093
  this._log = console.log.bind(console);
1089
1094
  }
@@ -1091,7 +1096,7 @@ class RoomSession {
1091
1096
  _getHandle(handleId, rfid = null) {
1092
1097
  return this._participants.find(p => p.handleId === handleId || (rfid && p.rfid === rfid));
1093
1098
  }
1094
-
1099
+
1095
1100
  _getStats(type = null) {
1096
1101
  return Promise.all(this._participants.map(participant => {
1097
1102
  let mediaTrack = null;
@@ -1105,7 +1110,7 @@ class RoomSession {
1105
1110
  .catch(e => Promise.resolve({handle: participant, stats: e}))
1106
1111
  }))
1107
1112
  }
1108
-
1113
+
1109
1114
  _sendTrickleCandidate(handleId, candidate) {
1110
1115
  return this._send({
1111
1116
  "janus": "trickle",
@@ -1113,9 +1118,9 @@ class RoomSession {
1113
1118
  "handle_id": handleId
1114
1119
  })
1115
1120
  }
1116
-
1121
+
1117
1122
  _webrtc(handleId, enableOntrack = false) {
1118
-
1123
+
1119
1124
  let handle = this._getHandle(handleId);
1120
1125
  if (!handle) {
1121
1126
  this.emit('error', {
@@ -1125,13 +1130,13 @@ class RoomSession {
1125
1130
  data: [handleId, 'create rtc connection']
1126
1131
  });
1127
1132
  }
1128
-
1133
+
1129
1134
  let config = handle.webrtcStuff;
1130
1135
  if (!config.pc) {
1131
1136
  let pc_config = {"iceServers": this.iceServers, "iceTransportPolicy": 'all', "bundlePolicy": undefined};
1132
-
1137
+
1133
1138
  pc_config["sdpSemantics"] = this.isUnifiedPlan ? "unified-plan" : "plan-b";
1134
-
1139
+
1135
1140
  let pc_constraints = {
1136
1141
  "optional": [{"DtlsSrtpKeyAgreement": true}]
1137
1142
  };
@@ -1142,9 +1147,9 @@ class RoomSession {
1142
1147
  // This is Edge, enable BUNDLE explicitly
1143
1148
  pc_config.bundlePolicy = "max-bundle";
1144
1149
  }
1145
-
1150
+
1146
1151
  this._log('new RTCPeerConnection', pc_config, pc_constraints);
1147
-
1152
+
1148
1153
  config.pc = new RTCPeerConnection(pc_config, pc_constraints);
1149
1154
  config.pc.onconnectionstatechange = () => {
1150
1155
  if (config.pc.connectionState === 'failed') {
@@ -1203,22 +1208,22 @@ class RoomSession {
1203
1208
  "sdpMid": event.candidate.sdpMid,
1204
1209
  "sdpMLineIndex": event.candidate.sdpMLineIndex
1205
1210
  };
1206
-
1211
+
1207
1212
  this._sendTrickleCandidate(handleId, candidate)
1208
1213
  .catch(e => {
1209
1214
  this.emit('error', e);
1210
1215
  });
1211
1216
  }
1212
1217
  };
1213
-
1218
+
1214
1219
  if (enableOntrack) {
1215
1220
  config.pc.ontrack = (event) => {
1216
-
1221
+
1217
1222
  if(!event.streams)
1218
- return;
1223
+ return;
1219
1224
 
1220
1225
  //config.stream = event.streams[0];
1221
-
1226
+
1222
1227
  if (!config.stream) {
1223
1228
  config.stream = new MediaStream();
1224
1229
  }
@@ -1238,10 +1243,10 @@ class RoomSession {
1238
1243
  hasAudioTrack: !!(config.stream && config.stream.getAudioTracks().length),
1239
1244
  hasVideoTrack: !!(config.stream && config.stream.getVideoTracks().length)
1240
1245
  });
1241
-
1246
+
1242
1247
  if (event.track.onended)
1243
1248
  return;
1244
-
1249
+
1245
1250
  event.track.onended = (ev) => {
1246
1251
 
1247
1252
  let mid = ev.target.id;
@@ -1269,7 +1274,7 @@ class RoomSession {
1269
1274
  });
1270
1275
  }
1271
1276
  };
1272
-
1277
+
1273
1278
  event.track.onmute = (ev) => {
1274
1279
  this._log('remoteTrackMuted', 'onmute');
1275
1280
 
@@ -1290,7 +1295,7 @@ class RoomSession {
1290
1295
  muted: true
1291
1296
  });
1292
1297
  };
1293
-
1298
+
1294
1299
  event.track.onunmute = (ev) => {
1295
1300
  this._log('remoteTrackMuted', 'onunmute');
1296
1301
 
@@ -1311,55 +1316,71 @@ class RoomSession {
1311
1316
  muted: false
1312
1317
  });
1313
1318
  };
1314
-
1319
+
1315
1320
  }
1316
-
1321
+
1317
1322
  };
1318
1323
  }
1319
1324
  }
1320
-
1321
- let defaultDataChannelLabel = 'JanusDataChannel';
1322
-
1325
+
1323
1326
  if (!config.dataChannel || !config.dataChannelOpen) {
1324
-
1327
+
1328
+ config.dataChannel = {};
1329
+
1325
1330
  var onDataChannelMessage = (event) => {
1326
1331
  this._handleDataEvents(handleId, 'message', event.data);
1327
1332
  };
1328
1333
  var onDataChannelStateChange = (event) => {
1329
- this._handleDataEvents(handleId, 'state', config.dataChannel.readyState);
1334
+ let label = event.target.label;
1335
+ let protocol = event.target.protocol;
1336
+ let state = config.dataChannel[label] ? config.dataChannel[label].readyState : "null";
1337
+ this._handleDataEvents(handleId, 'state', {state, label} );
1330
1338
  };
1339
+ //TODO: check this
1331
1340
  var onDataChannelError = (error) => {
1332
- this._handleDataEvents(handleId, 'error', error);
1341
+ this._handleDataEvents(handleId, 'error', {label: error?.channel?.label, error});
1333
1342
  };
1334
- // Until we implement the proxying of open requests within the Janus core, we open a channel ourselves whatever the case
1335
- config.dataChannel = config.pc.createDataChannel(defaultDataChannelLabel, {ordered: true});
1336
- config.dataChannel.onmessage = onDataChannelMessage;
1337
- config.dataChannel.onopen = onDataChannelStateChange;
1338
- config.dataChannel.onclose = onDataChannelStateChange;
1339
- config.dataChannel.onerror = onDataChannelError;
1340
-
1343
+
1344
+ const createDataChannel = (label, protocol, incoming) => {
1345
+ let options = {ordered: true};
1346
+ if(!incoming) {
1347
+ if(protocol) {
1348
+ options = {...options, protocol}
1349
+ }
1350
+ config.dataChannel[label] = config.pc.createDataChannel(label, options);
1351
+ }
1352
+ else {
1353
+ config.dataChannel[label] = incoming;
1354
+ }
1355
+
1356
+ config.dataChannel[label].onmessage = onDataChannelMessage;
1357
+ config.dataChannel[label].onopen = onDataChannelStateChange;
1358
+ config.dataChannel[label].onclose = onDataChannelStateChange;
1359
+ config.dataChannel[label].onerror = onDataChannelError;
1360
+ }
1361
+
1362
+ createDataChannel(this.defaultDataChannelLabel, null, null)
1341
1363
  config.pc.ondatachannel = function (event) {
1342
- //TODO: implement this
1343
- console.log('Janus is creating data channel');
1364
+ createDataChannel(event.channel.label, event.channel.protocol, event.channel)
1344
1365
  };
1345
1366
  }
1346
1367
  }
1347
-
1368
+
1348
1369
  _webrtcPeer(handleId, jsep) {
1349
-
1370
+
1350
1371
  let handle = this._getHandle(handleId);
1351
1372
  if (!handle) {
1352
1373
  return Promise.reject({type: 'warning', id: 15, message: 'id non-existent', data: [handleId, 'rtc peer']});
1353
1374
  }
1354
-
1375
+
1355
1376
  var config = handle.webrtcStuff;
1356
-
1377
+
1357
1378
  if (jsep !== undefined && jsep !== null) {
1358
1379
  if (config.pc === null) {
1359
1380
  this._log("No PeerConnection: if this is an answer, use createAnswer and not _webrtcPeer");
1360
1381
  return Promise.resolve(null);
1361
1382
  }
1362
-
1383
+
1363
1384
  return config.pc.setRemoteDescription(jsep)
1364
1385
  .then(() => {
1365
1386
  config.remoteSdp = jsep.sdp;
@@ -1382,20 +1403,20 @@ class RoomSession {
1382
1403
  return Promise.reject({type: 'warning', id: 22, message: 'rtc peer', data: [handleId, 'invalid jsep']});
1383
1404
  }
1384
1405
  }
1385
-
1406
+
1386
1407
  _iceRestart(handleId) {
1387
-
1408
+
1388
1409
  let handle = this._getHandle(handleId);
1389
1410
  if (!handle) {
1390
1411
  return;
1391
1412
  }
1392
1413
  var config = handle.webrtcStuff;
1393
-
1414
+
1394
1415
  // Already restarting;
1395
1416
  if (config.isIceRestarting) {
1396
1417
  return;
1397
1418
  }
1398
-
1419
+
1399
1420
  if (this.handleId === handleId) {
1400
1421
  this._log('Performing local ICE restart');
1401
1422
  config.isIceRestarting = true;
@@ -1430,11 +1451,11 @@ class RoomSession {
1430
1451
  config.isIceRestarting = false;
1431
1452
  });
1432
1453
  }
1433
-
1454
+
1434
1455
  }
1435
-
1456
+
1436
1457
  _createAO(type = 'offer', handleId, iceRestart = false, [audioSend, audioRecv, videoSend, videoRecv]) {
1437
-
1458
+
1438
1459
  let handle = this._getHandle(handleId);
1439
1460
  if (!handle) {
1440
1461
  return Promise.reject({
@@ -1444,16 +1465,16 @@ class RoomSession {
1444
1465
  data: [handleId, 'createAO', type]
1445
1466
  });
1446
1467
  }
1447
-
1468
+
1448
1469
  let methodName = null;
1449
1470
  if (type === 'offer') {
1450
1471
  methodName = 'createOffer'
1451
1472
  } else {
1452
1473
  methodName = 'createAnswer'
1453
1474
  }
1454
-
1475
+
1455
1476
  var config = handle.webrtcStuff;
1456
-
1477
+
1457
1478
  // https://code.google.com/p/webrtc/issues/detail?id=3508
1458
1479
  var mediaConstraints = {};
1459
1480
  if (this.isUnifiedPlan) {
@@ -1476,7 +1497,7 @@ class RoomSession {
1476
1497
  }
1477
1498
  }
1478
1499
  }
1479
-
1500
+
1480
1501
  // Handle audio (and related changes, if any)
1481
1502
  if (!audioSend && !audioRecv) {
1482
1503
  // Audio disabled: have we removed it?
@@ -1559,7 +1580,7 @@ class RoomSession {
1559
1580
  }
1560
1581
  }
1561
1582
  } else {
1562
-
1583
+
1563
1584
  if (adapter.browserDetails.browser === "firefox" || adapter.browserDetails.browser === "edge") {
1564
1585
  mediaConstraints = {
1565
1586
  offerToReceiveAudio: audioRecv,
@@ -1574,11 +1595,11 @@ class RoomSession {
1574
1595
  };
1575
1596
  }
1576
1597
  }
1577
-
1598
+
1578
1599
  if (iceRestart) {
1579
1600
  mediaConstraints["iceRestart"] = true;
1580
1601
  }
1581
-
1602
+
1582
1603
  return config.pc[methodName](mediaConstraints)
1583
1604
  .then(function (response) {
1584
1605
  config.mySdp = response.sdp;
@@ -1596,21 +1617,21 @@ class RoomSession {
1596
1617
  // Don't do anything until we have all candidates
1597
1618
  return Promise.resolve(null);
1598
1619
  }
1599
-
1620
+
1600
1621
  // JSON.stringify doesn't work on some WebRTC objects anymore
1601
1622
  // See https://code.google.com/p/chromium/issues/detail?id=467366
1602
1623
  var jsep = {
1603
1624
  "type": response.type,
1604
1625
  "sdp": response.sdp
1605
1626
  };
1606
-
1627
+
1607
1628
  return _p.then(() => jsep)
1608
1629
  }, (e) => {
1609
1630
  return Promise.reject({type: 'warning', id: 25, message: methodName, data: [handleId, e]})
1610
1631
  });
1611
-
1632
+
1612
1633
  }
1613
-
1634
+
1614
1635
  _publishRemote(handleId, jsep) {
1615
1636
  let handle = this._getHandle(handleId);
1616
1637
  if (!handle) {
@@ -1621,11 +1642,11 @@ class RoomSession {
1621
1642
  data: [handleId, 'publish remote participant']
1622
1643
  })
1623
1644
  }
1624
-
1645
+
1625
1646
  this._webrtc(handleId, true);
1626
-
1647
+
1627
1648
  let config = handle.webrtcStuff;
1628
-
1649
+
1629
1650
  if (jsep) {
1630
1651
  return config.pc.setRemoteDescription(jsep)
1631
1652
  .then(() => {
@@ -1667,19 +1688,19 @@ class RoomSession {
1667
1688
  message: 'setRemoteDescription',
1668
1689
  data: [handleId, e]
1669
1690
  }));
1670
-
1691
+
1671
1692
  } else {
1672
1693
  return Promise.resolve();
1673
1694
  }
1674
-
1695
+
1675
1696
  }
1676
-
1697
+
1677
1698
  //Public methods
1678
-
1699
+
1679
1700
  publishLocal(stream, {keepAudio = false, keepVideo = false} = {}) {
1680
-
1701
+
1681
1702
  this.emit('publishing', true);
1682
-
1703
+
1683
1704
  let handle = this._getHandle(this.handleId);
1684
1705
  if (!handle) {
1685
1706
  return Promise.reject({
@@ -1689,24 +1710,24 @@ class RoomSession {
1689
1710
  data: null
1690
1711
  })
1691
1712
  }
1692
-
1713
+
1693
1714
  this._webrtc(this.handleId);
1694
-
1715
+
1695
1716
  let config = handle.webrtcStuff;
1696
-
1717
+
1697
1718
  if (stream) {
1698
1719
  if (!config.stream) {
1699
1720
  config.stream = stream;
1700
1721
  stream.getTracks().forEach(function (track) {
1701
1722
  config.pc.addTrack(track, stream);
1702
1723
  });
1703
-
1724
+
1704
1725
  } else {
1705
-
1726
+
1706
1727
  /* UPDATE Audio */
1707
-
1728
+
1708
1729
  let replaceAudio = stream.getAudioTracks().length;
1709
-
1730
+
1710
1731
  if (replaceAudio || !keepAudio) {
1711
1732
  //this will stop existing tracks
1712
1733
  let oldAudioStream = config.stream.getAudioTracks()[0];
@@ -1719,7 +1740,7 @@ class RoomSession {
1719
1740
  }
1720
1741
  }
1721
1742
  }
1722
-
1743
+
1723
1744
  if (config.pc.getSenders() && config.pc.getSenders().length) {
1724
1745
  if (replaceAudio && this.isUnifiedPlan) {
1725
1746
  //using replace
@@ -1732,7 +1753,7 @@ class RoomSession {
1732
1753
  }
1733
1754
  }
1734
1755
  }
1735
-
1756
+
1736
1757
  if (replaceAudio) {
1737
1758
  config.stream.addTrack(stream.getAudioTracks()[0]);
1738
1759
  var audioTransceiver = null;
@@ -1749,19 +1770,19 @@ class RoomSession {
1749
1770
  }
1750
1771
  }
1751
1772
  }
1752
-
1773
+
1753
1774
  if (audioTransceiver && audioTransceiver.sender) {
1754
1775
  audioTransceiver.sender.replaceTrack(stream.getAudioTracks()[0]);
1755
1776
  } else {
1756
1777
  config.pc.addTrack(stream.getAudioTracks()[0], stream);
1757
1778
  }
1758
-
1779
+
1759
1780
  }
1760
-
1781
+
1761
1782
  /* UPDATE Video */
1762
-
1783
+
1763
1784
  let replaceVideo = stream.getVideoTracks().length;
1764
-
1785
+
1765
1786
  if (replaceVideo || !keepVideo) {
1766
1787
  let oldVideoStream = config.stream.getVideoTracks()[0];
1767
1788
  if (oldVideoStream) {
@@ -1773,7 +1794,7 @@ class RoomSession {
1773
1794
  }
1774
1795
  }
1775
1796
  }
1776
-
1797
+
1777
1798
  if (config.pc.getSenders() && config.pc.getSenders().length) {
1778
1799
  if (replaceVideo && this.isUnifiedPlan) {
1779
1800
  //using replace
@@ -1786,7 +1807,7 @@ class RoomSession {
1786
1807
  }
1787
1808
  }
1788
1809
  }
1789
-
1810
+
1790
1811
  if (replaceVideo) {
1791
1812
  config.stream.addTrack(stream.getVideoTracks()[0]);
1792
1813
  var videoTransceiver = null;
@@ -1812,17 +1833,17 @@ class RoomSession {
1812
1833
  }
1813
1834
  }
1814
1835
  }
1815
-
1836
+
1816
1837
  let hasAudio = !!(stream && stream.getAudioTracks().length > 0);
1817
1838
  let hasVideo = !!(stream && stream.getVideoTracks().length > 0);
1818
1839
  let isAudioMuted = !stream || stream.getAudioTracks().length === 0 || !stream.getAudioTracks()[0].enabled;
1819
1840
  let isVideoMuted = !stream || stream.getVideoTracks().length === 0 || !stream.getVideoTracks()[0].enabled;
1820
-
1841
+
1821
1842
  this.isAudioEnabed = hasAudio;
1822
1843
  this.isVideoEnabled = hasVideo;
1823
1844
  this.isAudioMuted = isAudioMuted;
1824
1845
  this.isVideoMuted = isVideoMuted;
1825
-
1846
+
1826
1847
  return this._createAO('offer', this.handleId, false, [hasAudio, false, hasVideo, false])
1827
1848
  .then((jsep) => {
1828
1849
  if (!jsep) {
@@ -1844,12 +1865,12 @@ class RoomSession {
1844
1865
  return new Promise((resolve, reject) => {
1845
1866
  let __ = (val) => {
1846
1867
  if (val) {
1847
- clearTimeout(___);
1868
+ clearTimeout(this._dataChannelTimeoutId);
1848
1869
  this.off('dataChannel', __, this);
1849
1870
  resolve(this);
1850
1871
  }
1851
1872
  };
1852
- let ___ = setTimeout(() => {
1873
+ this._dataChannelTimeoutId = setTimeout(() => {
1853
1874
  this.off('dataChannel', __, this);
1854
1875
  reject({type: 'error', id: 27, message: 'Data channel did not open', data: null});
1855
1876
  }, 5000);
@@ -1920,7 +1941,7 @@ class RoomSession {
1920
1941
  return Promise.reject(e);
1921
1942
  })
1922
1943
  }
1923
-
1944
+
1924
1945
  unpublishLocal(dontWait = false) {
1925
1946
  return this._isPublished
1926
1947
  ? this.sendMessage(this.handleId, {body: {"request": "unpublish"}}, dontWait)
@@ -1931,7 +1952,7 @@ class RoomSession {
1931
1952
  })
1932
1953
  : Promise.resolve()
1933
1954
  }
1934
-
1955
+
1935
1956
  toggleAudio(value = null, mid) {
1936
1957
  let handle = this._getHandle(this.handleId);
1937
1958
  if (!handle) {
@@ -1953,14 +1974,14 @@ class RoomSession {
1953
1974
  }
1954
1975
  this.emit('localMuted', {type: 'audio', value: this.isAudioMuted, mid});
1955
1976
  }
1956
-
1977
+
1957
1978
  toggleVideo(value = null, mid) {
1958
1979
  let handle = this._getHandle(this.handleId);
1959
1980
  if (!handle) {
1960
1981
  return Promise.reject({type: 'error', id: 21, message: 'no local id, connect first', data: null})
1961
1982
  }
1962
1983
  let config = handle.webrtcStuff;
1963
-
1984
+
1964
1985
  if (this.isUnifiedPlan) {
1965
1986
  let transceiver = config.pc.getTransceivers()
1966
1987
  .find(t => t.sender && t.sender.track && t.receiver.track.kind === "video" && t.stopped === false && (mid ? t.mid === mid : true));
@@ -1977,25 +1998,25 @@ class RoomSession {
1977
1998
  }
1978
1999
  this.emit('localMuted', {type: 'video', value: this.isVideoMuted, mid});
1979
2000
  }
1980
-
2001
+
1981
2002
  setInstructorId(instructorId = null) {
1982
2003
  this._instuctorId = instructorId;
1983
2004
  this.emit('instructorId', this._instuctorId);
1984
2005
  return this._instuctorId;
1985
2006
  }
1986
-
2007
+
1987
2008
  setObserverIds(observerIds = []) {
1988
2009
  this._observerIds = observerIds;
1989
2010
  this.emit('observerIds', this._observerIds);
1990
2011
  return this._observerIds;
1991
2012
  }
1992
-
2013
+
1993
2014
  setTalkbackIds(talkbackIds = []) {
1994
2015
  this._talkbackIds = talkbackIds;
1995
2016
  this.emit('talkbackIds', this._talkbackIds);
1996
2017
  return this._talkbackIds;
1997
2018
  }
1998
-
2019
+
1999
2020
  }
2000
2021
 
2001
2022
  export default Room;