@webex/plugin-meetings 3.0.0-beta.1 → 3.0.0-beta.2

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.
Files changed (111) hide show
  1. package/dist/common/errors/webex-errors.js +5 -29
  2. package/dist/common/errors/webex-errors.js.map +1 -1
  3. package/dist/constants.js +15 -74
  4. package/dist/constants.js.map +1 -1
  5. package/dist/media/index.js +68 -213
  6. package/dist/media/index.js.map +1 -1
  7. package/dist/media/internal-media-core-wrapper.js +22 -0
  8. package/dist/media/internal-media-core-wrapper.js.map +1 -0
  9. package/dist/media/properties.js +20 -25
  10. package/dist/media/properties.js.map +1 -1
  11. package/dist/media/util.js +0 -27
  12. package/dist/media/util.js.map +1 -1
  13. package/dist/meeting/index.js +694 -432
  14. package/dist/meeting/index.js.map +1 -1
  15. package/dist/meeting/request.js +1 -0
  16. package/dist/meeting/request.js.map +1 -1
  17. package/dist/meeting/util.js +3 -44
  18. package/dist/meeting/util.js.map +1 -1
  19. package/dist/meetings/index.js +64 -5
  20. package/dist/meetings/index.js.map +1 -1
  21. package/dist/meetings/util.js +24 -1
  22. package/dist/meetings/util.js.map +1 -1
  23. package/dist/members/index.js +68 -0
  24. package/dist/members/index.js.map +1 -1
  25. package/dist/multistream/mediaRequestManager.js +132 -0
  26. package/dist/multistream/mediaRequestManager.js.map +1 -0
  27. package/dist/multistream/multistreamMedia.js +116 -0
  28. package/dist/multistream/multistreamMedia.js.map +1 -0
  29. package/dist/multistream/receiveSlot.js +209 -0
  30. package/dist/multistream/receiveSlot.js.map +1 -0
  31. package/dist/multistream/receiveSlotManager.js +195 -0
  32. package/dist/multistream/receiveSlotManager.js.map +1 -0
  33. package/dist/multistream/remoteMedia.js +284 -0
  34. package/dist/multistream/remoteMedia.js.map +1 -0
  35. package/dist/multistream/remoteMediaGroup.js +243 -0
  36. package/dist/multistream/remoteMediaGroup.js.map +1 -0
  37. package/dist/multistream/remoteMediaManager.js +1113 -0
  38. package/dist/multistream/remoteMediaManager.js.map +1 -0
  39. package/dist/reconnection-manager/index.js +109 -130
  40. package/dist/reconnection-manager/index.js.map +1 -1
  41. package/dist/roap/index.js +57 -240
  42. package/dist/roap/index.js.map +1 -1
  43. package/dist/roap/request.js +2 -114
  44. package/dist/roap/request.js.map +1 -1
  45. package/dist/roap/turnDiscovery.js +11 -5
  46. package/dist/roap/turnDiscovery.js.map +1 -1
  47. package/dist/statsAnalyzer/global.js +2 -0
  48. package/dist/statsAnalyzer/global.js.map +1 -1
  49. package/dist/statsAnalyzer/index.js +39 -36
  50. package/dist/statsAnalyzer/index.js.map +1 -1
  51. package/package.json +20 -19
  52. package/src/common/errors/webex-errors.js +0 -18
  53. package/src/constants.ts +139 -180
  54. package/src/media/index.js +60 -194
  55. package/src/media/internal-media-core-wrapper.ts +9 -0
  56. package/src/media/properties.js +19 -25
  57. package/src/media/util.js +0 -22
  58. package/src/meeting/index.js +565 -320
  59. package/src/meeting/request.js +1 -0
  60. package/src/meeting/util.js +3 -46
  61. package/src/meetings/index.js +30 -1
  62. package/src/meetings/util.js +23 -2
  63. package/src/members/index.js +48 -0
  64. package/src/multistream/mediaRequestManager.ts +164 -0
  65. package/src/multistream/multistreamMedia.ts +92 -0
  66. package/src/multistream/receiveSlot.ts +141 -0
  67. package/src/multistream/receiveSlotManager.ts +142 -0
  68. package/src/multistream/remoteMedia.ts +219 -0
  69. package/src/multistream/remoteMediaGroup.ts +224 -0
  70. package/src/multistream/remoteMediaManager.ts +911 -0
  71. package/src/reconnection-manager/index.js +40 -53
  72. package/src/roap/index.js +47 -207
  73. package/src/roap/request.js +1 -72
  74. package/src/roap/turnDiscovery.ts +12 -6
  75. package/src/statsAnalyzer/global.js +2 -0
  76. package/src/statsAnalyzer/index.js +32 -46
  77. package/test/integration/spec/journey.js +1 -1
  78. package/test/unit/spec/media/index.ts +223 -0
  79. package/test/unit/spec/media/properties.ts +73 -82
  80. package/test/unit/spec/meeting/effectsState.js +1 -3
  81. package/test/unit/spec/meeting/index.js +420 -228
  82. package/test/unit/spec/meeting/muteState.js +7 -0
  83. package/test/unit/spec/meeting/utils.js +61 -2
  84. package/test/unit/spec/meetings/index.js +0 -4
  85. package/test/unit/spec/members/index.js +164 -2
  86. package/test/unit/spec/multistream/mediaRequestManager.ts +511 -0
  87. package/test/unit/spec/multistream/receiveSlot.ts +104 -0
  88. package/test/unit/spec/multistream/receiveSlotManager.ts +173 -0
  89. package/test/unit/spec/multistream/remoteMedia.ts +217 -0
  90. package/test/unit/spec/multistream/remoteMediaGroup.ts +396 -0
  91. package/test/unit/spec/multistream/remoteMediaManager.ts +1251 -0
  92. package/test/unit/spec/roap/index.ts +63 -35
  93. package/test/unit/spec/stats-analyzer/index.js +19 -22
  94. package/dist/peer-connection-manager/index.js +0 -794
  95. package/dist/peer-connection-manager/index.js.map +0 -1
  96. package/dist/roap/collection.js +0 -73
  97. package/dist/roap/collection.js.map +0 -1
  98. package/dist/roap/handler.js +0 -337
  99. package/dist/roap/handler.js.map +0 -1
  100. package/dist/roap/state.js +0 -164
  101. package/dist/roap/state.js.map +0 -1
  102. package/dist/roap/util.js +0 -102
  103. package/dist/roap/util.js.map +0 -1
  104. package/src/peer-connection-manager/index.js +0 -723
  105. package/src/roap/collection.js +0 -63
  106. package/src/roap/handler.js +0 -252
  107. package/src/roap/state.js +0 -149
  108. package/src/roap/util.js +0 -93
  109. package/test/unit/spec/peerconnection-manager/index.js +0 -188
  110. package/test/unit/spec/peerconnection-manager/utils.js +0 -48
  111. package/test/unit/spec/roap/util.js +0 -30
@@ -18,11 +18,9 @@ import {
18
18
  import BEHAVIORAL_METRICS from '../metrics/constants';
19
19
  import ReconnectionError from '../common/errors/reconnection';
20
20
  import ReconnectInProgress from '../common/errors/reconnection-in-progress';
21
- import PeerConnectionManager from '../peer-connection-manager';
22
21
  import {eventType, reconnection, errorObjects} from '../metrics/config';
23
22
  import Media from '../media';
24
23
  import Metrics from '../metrics';
25
- import RoapCollection from '../roap/collection';
26
24
 
27
25
  /**
28
26
  * Used to indicate that the reconnect logic needs to be retried.
@@ -119,6 +117,21 @@ export default class ReconnectionManager {
119
117
  this.reset();
120
118
  }
121
119
 
120
+ /**
121
+ * @public
122
+ * @memberof ReconnectionManager
123
+ * @returns {void}
124
+ */
125
+ resetReconnectionTimer() {
126
+ this.iceState.resolve();
127
+ this.iceState.resolve = () => {};
128
+
129
+ if (this.iceState.timer) {
130
+ clearTimeout(this.iceState.timer);
131
+ delete this.iceState.timer;
132
+ }
133
+ }
134
+
122
135
  /**
123
136
  * Sets the iceState to connected and clears any disconnect timeouts and
124
137
  * related timeout data within the iceState.
@@ -131,13 +144,7 @@ export default class ReconnectionManager {
131
144
  if (this.iceState.disconnected) {
132
145
  LoggerProxy.logger.log('ReconnectionManager:index#iceReconnected --> ice has reconnected');
133
146
 
134
- this.iceState.resolve();
135
- this.iceState.resolve = () => {};
136
-
137
- if (this.iceState.timer) {
138
- clearTimeout(this.iceState.timer);
139
- delete this.iceState.timer;
140
- }
147
+ this.resetReconnectionTimer();
141
148
 
142
149
  this.iceState.disconnected = false;
143
150
  }
@@ -199,6 +206,16 @@ export default class ReconnectionManager {
199
206
  this.meeting = null;
200
207
  }
201
208
 
209
+
210
+ /**
211
+ * @public
212
+ * @memberof ReconnectionManager
213
+ * @returns {Boolean} true if reconnection operation is in progress
214
+ */
215
+ isReconnectInProgress() {
216
+ return (this.status === RECONNECTION.STATE.IN_PROGRESS);
217
+ }
218
+
202
219
  /**
203
220
  * @returns {Boolean}
204
221
  * @throws {ReconnectionError}
@@ -388,13 +405,10 @@ export default class ReconnectionManager {
388
405
  async rejoinMeeting(wasSharing = false) {
389
406
  try {
390
407
  LoggerProxy.logger.info('ReconnectionManager:index#rejoinMeeting --> attemping meeting rejoin');
391
- const previousCorrelationId = this.meeting.correlationId;
392
408
 
393
409
  await this.meeting.join({rejoin: true});
394
410
  LoggerProxy.logger.info('ReconnectionManager:index#rejoinMeeting --> meeting rejoined');
395
411
 
396
- RoapCollection.deleteSession(previousCorrelationId);
397
-
398
412
  if (wasSharing) {
399
413
  // Stop the share streams if user tried to rejoin
400
414
  Media.stopTracks(this.meeting.mediaProperties.shareTrack);
@@ -451,28 +465,22 @@ export default class ReconnectionManager {
451
465
  * @private
452
466
  * @memberof ReconnectionManager
453
467
  */
454
- reconnectMedia() {
468
+ async reconnectMedia() {
455
469
  LoggerProxy.logger.log('ReconnectionManager:index#reconnectMedia --> Begin reestablishment of media');
456
470
 
457
- return ReconnectionManager.setupPeerConnection(this.meeting)
458
- .then(() => Media.attachMedia(this.meeting.mediaProperties, {
459
- meetingId: this.meeting.id,
460
- remoteQualityLevel: this.meeting.mediaProperties.remoteQualityLevel,
461
- enableRtx: this.meeting.config.enableRtx,
462
- enableExtmap: this.meeting.config.enableExtmap
463
- }))
464
- .then((peerConnection) => this.meeting.setRemoteStream(peerConnection))
465
- .then(() => {
466
- LoggerProxy.logger.log('ReconnectionManager:index#reconnectMedia --> Sending ROAP media request');
467
-
468
- return this.meeting.roap
469
- .sendRoapMediaRequest({
470
- sdp: this.meeting.mediaProperties.peerConnection.sdp,
471
- roapSeq: this.meeting.roapSeq,
472
- meeting: this.meeting,
473
- reconnect: true
474
- });
475
- });
471
+ // we are not simply calling this.meeting.mediaProperties.webrtcMediaConnection.reconnect(),
472
+ // but instead manually closing and creating new media connection, because we need to do the TURN discovery again
473
+
474
+ await this.meeting.closePeerConnections();
475
+ this.meeting.mediaProperties.unsetPeerConnection();
476
+
477
+ const turnServerInfo = await this.meeting.roap.doTurnDiscovery(this.meeting, true);
478
+
479
+ const mc = this.meeting.createMediaConnection(turnServerInfo);
480
+
481
+ this.meeting.statsAnalyzer.updateMediaConnection(mc);
482
+
483
+ return mc.initiateOffer();
476
484
  }
477
485
 
478
486
  /**
@@ -508,25 +516,4 @@ export default class ReconnectionManager {
508
516
  throw (connectError);
509
517
  }
510
518
  }
511
-
512
- /**
513
- * @param {Meeting} meeting
514
- * @returns {undefined}
515
- * @private
516
- * @memberof ReconnectionManager
517
- */
518
- static async setupPeerConnection(meeting) {
519
- LoggerProxy.logger.log('ReconnectionManager:index#setupPeerConnection --> Begin resetting peer connection');
520
- // close pcs, unset to null and create a new one with out closing any streams
521
- PeerConnectionManager.close(meeting.mediaProperties.peerConnection);
522
- meeting.mediaProperties.unsetPeerConnection();
523
-
524
- const turnInfo = await meeting.roap.doTurnDiscovery(meeting, true);
525
-
526
- meeting.mediaProperties.reInitiatePeerconnection(turnInfo);
527
- PeerConnectionManager.setPeerConnectionEvents(meeting);
528
-
529
- // update the peerconnection in the stats manager when ever we reconnect
530
- meeting.statsAnalyzer.updatePeerconnection(meeting.mediaProperties.peerConnection);
531
- }
532
519
  }
package/src/roap/index.js CHANGED
@@ -2,11 +2,8 @@ import {StatelessWebexPlugin} from '@webex/webex-core';
2
2
 
3
3
  import {ROAP} from '../constants';
4
4
  import LoggerProxy from '../common/logs/logger-proxy';
5
- import MeetingUtil from '../meeting/util';
6
5
 
7
- import RoapHandler from './handler';
8
6
  import RoapRequest from './request';
9
- import RoapCollection from './collection';
10
7
  import TurnDiscovery from './turnDiscovery';
11
8
 
12
9
  /**
@@ -14,8 +11,9 @@ import TurnDiscovery from './turnDiscovery';
14
11
  * @typedef {Object} RoapOptions
15
12
  * @property {String} sdp
16
13
  * @property {Meeting} meeting
17
- * @property {Number} roapSeq
18
- * @property {Boolean} reconnect
14
+ * @property {Number} seq
15
+ * @property {Number} tieBreaker
16
+ * @property {Boolean} reconnect
19
17
  */
20
18
 
21
19
  /**
@@ -52,14 +50,6 @@ export default class Roap extends StatelessWebexPlugin {
52
50
  * @memberof Roap
53
51
  */
54
52
  this.options = options;
55
- /**
56
- * The Roap Process State Handler
57
- * @instance
58
- * @type {RoapHandler}
59
- * @private
60
- * @memberof Roap
61
- */
62
- this.roapHandler = new RoapHandler(this.attrs, this.options, this.sendRoapOK.bind(this), this.sendRoapAnswer.bind(this), this.roapFinished.bind(this));
63
53
  /**
64
54
  * The Roap Request Server Proxy Object
65
55
  * @instance
@@ -68,63 +58,10 @@ export default class Roap extends StatelessWebexPlugin {
68
58
  * @memberof Roap
69
59
  */
70
60
  this.roapRequest = new RoapRequest({}, options);
71
- /**
72
- * The last roap offer sent to server and acked
73
- * @instance
74
- * @type {Object}
75
- * @private
76
- * @memberof Roap
77
- */
78
- this.lastRoapOffer = {};
79
61
 
80
62
  this.turnDiscovery = new TurnDiscovery(this.roapRequest);
81
63
  }
82
64
 
83
- /**
84
- * Starts listening to mercury events for Roap messages
85
- * @param {object} data event object
86
- * @returns {Promise}
87
- * @private
88
- * @memberof Roap
89
- */
90
- roapEvent(data) {
91
- const msg = data.message;
92
- const {correlationId} = data;
93
-
94
- LoggerProxy.logger.log(`Roap:index#roapEvent --> Received Roap Message [${JSON.stringify(msg, null, 2)}]`);
95
-
96
- if (msg.messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {
97
- // turn discovery is not part of normal roap protocol and so we are not handling it
98
- // through the usual roap state machine
99
- this.turnDiscovery.handleTurnDiscoveryResponse(msg);
100
- }
101
- else {
102
- this.roapHandler.submit({
103
- type: ROAP.RECEIVE_ROAP_MSG,
104
- msg,
105
- correlationId
106
- });
107
- }
108
- }
109
-
110
- /**
111
- *
112
- * @param {String} correlationId correlation id of a meeting
113
- * @param {Number} seq ROAP sequence number
114
- * @returns {Promise}
115
- * @private
116
- * @memberof Roap
117
- */
118
- stop(correlationId, seq) {
119
- this.roapHandler.submit({
120
- type: ROAP.RECEIVE_CALL_LEAVE,
121
- seq,
122
- correlationId
123
- });
124
-
125
- return Promise.resolve();
126
- }
127
-
128
65
  /**
129
66
  *
130
67
  * @param {SeqOptions} options
@@ -151,22 +88,15 @@ export default class Roap extends StatelessWebexPlugin {
151
88
  correlationId: options.correlationId,
152
89
  audioMuted: meeting.isAudioMuted(),
153
90
  videoMuted: meeting.isVideoMuted(),
154
- meetingId: meeting.id
91
+ meetingId: meeting.id,
92
+ preferTranscoding: !meeting.isMultistream,
155
93
  })
156
94
  .then(() => {
157
- this.roapHandler.submit({
158
- type: ROAP.SEND_ROAP_MSG,
159
- msg: roapMessage,
160
- correlationId: options.correlationId
161
- });
162
95
  LoggerProxy.logger.log(`Roap:index#sendRoapOK --> ROAP OK sent with seq ${options.seq}`);
163
- meeting.setRoapSeq(options.seq);
164
96
  });
165
97
  });
166
98
  }
167
99
 
168
- // eslint-disable-next-line no-warning-comments
169
- // TODO: try to merge sendRoapOk and roapAnswer
170
100
  /**
171
101
  * Sends a ROAP answer...
172
102
  * @param {SeqOptions} options
@@ -180,56 +110,54 @@ export default class Roap extends StatelessWebexPlugin {
180
110
  const meeting = this.webex.meetings.meetingCollection.getByKey('correlationId', options.correlationId);
181
111
  const roapMessage = {
182
112
  messageType: ROAP.ROAP_TYPES.ANSWER,
183
- sdps: options.sdps,
113
+ sdps: [options.sdp],
184
114
  version: ROAP.ROAP_VERSION,
185
115
  seq: options.seq
186
116
  };
187
117
 
188
- this.roapHandler.submit({
189
- type: ROAP.SEND_ROAP_MSG,
190
- msg: roapMessage,
191
- correlationId: options.correlationId
192
- });
193
-
194
118
  return this.roapRequest
195
119
  .sendRoap({
196
120
  roapMessage,
197
121
  locusSelfUrl: meeting.selfUrl,
198
122
  mediaId: options.mediaId,
199
123
  correlationId: options.correlationId,
200
- audioMuted: options.audioMuted,
201
- videoMuted: options.videoMuted,
202
- meetingId: meeting.id
203
- })
204
- .then(() => {
205
- meeting.setRoapSeq(options.seq);
206
-
207
- this.roapHandler.submit({
208
- type: ROAP.SEND_ROAP_MSG_SUCCESS,
209
- seq: roapMessage.seq,
210
- correlationId: meeting.correlationId
211
- });
124
+ audioMuted: meeting.isAudioMuted(),
125
+ videoMuted: meeting.isVideoMuted(),
126
+ meetingId: meeting.id,
127
+ preferTranscoding: !meeting.isMultistream,
212
128
  });
213
129
  }
214
130
 
215
131
  /**
216
132
  * Sends a ROAP error...
217
- * @param {Object} session
218
- * @param {Object} locus
219
- * @param {String} errorType
133
+ * @param {Object} options
220
134
  * @returns {Promise}
221
135
  * @private
222
136
  * @memberof Roap
223
137
  */
224
- sendRoapError(session, locus, errorType) {
225
- const msg = {
138
+ sendRoapError(options) {
139
+ const meeting = this.webex.meetings.meetingCollection.getByKey('correlationId', options.correlationId);
140
+ const roapMessage = {
226
141
  messageType: ROAP.ROAP_TYPES.ERROR,
227
142
  version: ROAP.ROAP_VERSION,
228
- errorType,
229
- seq: session.OFFER.seq
143
+ errorType: options.errorType,
144
+ seq: options.seq
145
+
230
146
  };
231
147
 
232
- return this.roapRequest.sendRoap(msg, locus);
148
+ return this.roapRequest.sendRoap({
149
+ roapMessage,
150
+ locusSelfUrl: meeting.selfUrl,
151
+ mediaId: options.mediaId,
152
+ correlationId: options.correlationId,
153
+ audioMuted: meeting.isAudioMuted(),
154
+ videoMuted: meeting.isVideoMuted(),
155
+ meetingId: meeting.id,
156
+ preferTranscoding: !meeting.isMultistream,
157
+ })
158
+ .then(() => {
159
+ LoggerProxy.logger.log(`Roap:index#sendRoapError --> ROAP ERROR sent with seq ${options.seq}`);
160
+ });
233
161
  }
234
162
 
235
163
  /**
@@ -240,22 +168,17 @@ export default class Roap extends StatelessWebexPlugin {
240
168
  * @memberof Roap
241
169
  */
242
170
  sendRoapMediaRequest(options) {
243
- const {meeting, reconnect} = options;
171
+ const {
172
+ meeting, seq, sdp, reconnect, tieBreaker
173
+ } = options;
244
174
  const roapMessage = {
245
175
  messageType: ROAP.ROAP_TYPES.OFFER,
246
- sdps: [options.sdp],
247
- // sdps: [options.sdp],
176
+ sdps: [sdp],
248
177
  version: ROAP.ROAP_VERSION,
249
- seq: typeof options.roapSeq !== 'number' && Number.isNaN(parseFloat(options.roapSeq)) ? 0 : options.roapSeq + 1,
250
- tieBreaker: 4294967294 // Math.floor(Math.random() * (2 ** 32) - 1) // TODO: Handle the roap conflict scenario
178
+ seq,
179
+ tieBreaker
251
180
  };
252
181
 
253
- this.roapHandler.submit({
254
- type: ROAP.SEND_ROAP_MSG,
255
- msg: roapMessage,
256
- correlationId: meeting.correlationId
257
- });
258
-
259
182
  // When reconnecting, it's important that the first roap message being sent out has empty media id.
260
183
  // Normally this is the roap offer, but when TURN discovery is enabled,
261
184
  // then this is the TURN discovery request message
@@ -269,111 +192,28 @@ export default class Roap extends StatelessWebexPlugin {
269
192
  mediaId: sendEmptyMediaId ? '' : meeting.mediaId,
270
193
  audioMuted: meeting.isAudioMuted(),
271
194
  videoMuted: meeting.isVideoMuted(),
272
- meetingId: meeting.id
195
+ meetingId: meeting.id,
196
+ preferTranscoding: !meeting.isMultistream,
273
197
  })
274
198
  .then(({locus, mediaConnections}) => {
275
- this.roapHandler.submit({
276
- type: ROAP.SEND_ROAP_MSG_SUCCESS,
277
- seq: roapMessage.seq,
278
- correlationId: meeting.correlationId
279
- });
280
- meeting.setRoapSeq(roapMessage.seq);
281
-
282
199
  if (mediaConnections) {
283
200
  meeting.updateMediaConnections(mediaConnections);
284
201
  }
285
202
 
286
- // eslint-disable-next-line no-warning-comments
287
- // TODO: we need to attach peerconenction to locus not sure if we need to pass everything here
288
203
  return locus;
289
- // eslint-disable-next-line no-warning-comments
290
- // TODO: check where to update the sequence number
291
204
  });
292
205
  }
293
206
 
294
207
  /**
295
- * sends a roap media request
296
- * @param {RoapOptions} options
297
- * @returns {Promise}
298
- * @private
299
- * @memberof Roap
300
- */
301
- sendRoapCallRequest = (options) => {
302
- const {meeting} = options;
303
- const roapMessage = {
304
- messageType: ROAP.ROAP_TYPES.OFFER,
305
- sdps: [options.sdp],
306
- version: ROAP.ROAP_VERSION,
307
- seq: typeof options.roapSeq !== 'number' && Number.isNaN(parseFloat(options.roapSeq)) ? 0 : options.roapSeq + 1,
308
- tieBreaker: 4294967294 // Math.floor(Math.random() * (2 ** 32) - 1) // TODO: Handle the roap conflict scenario
309
- };
310
-
311
- this.roapHandler.submit({
312
- type: ROAP.SEND_ROAP_MSG,
313
- msg: roapMessage,
314
- correlationId: meeting.correlationId
315
- });
316
-
317
- const roapBody = {
318
- localMedias: [
319
- {
320
- localSdp: JSON.stringify(this.roapRequest.attachRechabilityData({
321
- roapMessage,
322
- // eslint-disable-next-line no-warning-comments
323
- // TODO: check whats the need for video and audiomute
324
- audioMuted: !!meeting.isAudioMuted(),
325
- videoMuted: !!meeting.isVideoMuted()
326
- }))
327
- // mediaId: meeting.mediaId
328
- }
329
- ]
330
- };
331
-
332
- return MeetingUtil.joinMeetingOptions(meeting, {roapMessage: roapBody})
333
- .then((locus) => {
334
- this.roapHandler.submit({
335
- type: ROAP.SEND_ROAP_MSG_SUCCESS,
336
- seq: roapMessage.seq,
337
- correlationId: meeting.correlationId
338
- });
339
- meeting.setRoapSeq(roapMessage.seq);
340
-
341
- // eslint-disable-next-line no-warning-comments
342
- // TODO: we need to attach peerconenction to locus not sure if we need to pass everything here
343
- return locus;
344
- // eslint-disable-next-line no-warning-comments
345
- // TODO: check where to update the sequence number
346
- });
347
- };
348
-
349
- /**
350
- * Called when the roap sequence is finished (completed successfully or failed)
351
- * @param {String} correlationId id of the meeting affected
352
- * @param {String} sequenceId the id of the finished sequence
353
- * @returns {undefined}
354
- * @private
355
- * @memberof Roap
356
- */
357
- roapFinished(correlationId, sequenceId) {
358
- RoapCollection.onSessionSequenceFinish(correlationId, sequenceId);
359
- const meeting = this.webex.meetings.meetingCollection.getByKey('correlationId', correlationId);
360
-
361
- meeting.mediaNegotiatedEvent();
362
- if (!RoapCollection.isBusy(correlationId)) {
363
- meeting.processNextQueuedMediaUpdate();
364
- }
365
- }
366
-
367
- /**
368
- * Performs a TURN server discovery procedure, which involves exchanging
369
- * some roap messages with the server. This exchange has to be done before
370
- * any other roap messages are sent
371
- *
372
- * @param {Meeting} meeting
373
- * @param {Boolean} isReconnecting should be set to true if this is a new
374
- * media connection just after a reconnection
375
- * @returns {Promise}
376
- */
208
+ * Performs a TURN server discovery procedure, which involves exchanging
209
+ * some roap messages with the server. This exchange has to be done before
210
+ * any other roap messages are sent
211
+ *
212
+ * @param {Meeting} meeting
213
+ * @param {Boolean} isReconnecting should be set to true if this is a new
214
+ * media connection just after a reconnection
215
+ * @returns {Promise}
216
+ */
377
217
  doTurnDiscovery(meeting, isReconnecting) {
378
218
  return this.turnDiscovery.doTurnDiscovery(meeting, isReconnecting);
379
219
  }
@@ -4,16 +4,13 @@ import {StatelessWebexPlugin} from '@webex/webex-core';
4
4
 
5
5
  import LoggerProxy from '../common/logs/logger-proxy';
6
6
  import {
7
- PARTICIPANT,
8
- LOCI,
9
- CALL,
10
7
  MEDIA,
11
8
  HTTP_VERBS,
12
9
  REACHABILITY
13
10
  } from '../constants';
14
11
  import Metrics from '../metrics';
15
12
  import {eventType} from '../metrics/config';
16
- import ParameterError from '../common/errors/parameter';
13
+
17
14
  /**
18
15
  * @class RoapRequest
19
16
  */
@@ -45,74 +42,6 @@ export default class RoapRequest extends StatelessWebexPlugin {
45
42
  return localSdp;
46
43
  }
47
44
 
48
- joinMeetingWithRoap(options) {
49
- LoggerProxy.logger.info('Roap:request#joinMeetingWithRoap --> Join locus with roap');
50
- LoggerProxy.logger.info(`Roap:request#joinMeetingWithRoap --> Local SDP: ${options.roapMessage}`);
51
-
52
- return Promise.resolve().then(async () => {
53
- const deviceUrl = this.webex.internal.device.url;
54
- let url = '';
55
-
56
- const body = {
57
- deviceUrl,
58
- usingResource: options.resourceId || null,
59
- correlationId: options.correlationId,
60
- localMedias: [
61
- {
62
- localSdp: JSON.stringify(this.attachRechabilityData({
63
- roapMessage: options.roapMessage,
64
- audioMuted: false,
65
- videoMuted: false
66
- }))
67
- }
68
- ],
69
- clientMediaPreferences: {
70
- preferTranscoding: options.preferTranscoding ?? true
71
- }
72
- };
73
-
74
- if (options.locusUrl) {
75
- url = `${options.locusUrl}/${PARTICIPANT}`;
76
- }
77
- else if (options.sipUrl) {
78
- try {
79
- await this.webex.internal.services.waitForCatalog('postauth');
80
- url = `${this.webex.internal.services.get('locus')}/${LOCI}/${CALL}`;
81
- body.invitee = {
82
- address: options.sipTarget
83
- };
84
- }
85
- catch (e) {
86
- LoggerProxy.logger.error(`Roap:request#joinMeetingWithRoap --> ${e}`);
87
- throw (e);
88
- }
89
- }
90
- else {
91
- throw new ParameterError('Must provide a locusUrl or sipTarget');
92
- }
93
-
94
- return this.webex
95
- .request({
96
- method: HTTP_VERBS.POST,
97
- uri: url,
98
- body
99
- })
100
- .then((res) => {
101
- const {locus} = res.body;
102
-
103
- locus.roapSeq = options.roapMessage.seq;
104
- locus.id = locus.url.split('/').pop();
105
- LoggerProxy.logger.info(`Roap:request#joinMeetingWithRoap --> Joined locus [${locus.id}][${locus.fullState.lastActive}]`);
106
-
107
- return locus;
108
- })
109
- .catch((err) => {
110
- LoggerProxy.logger.error(`Roap:request#joinMeetingWithRoap --> failed with error: ${err}`);
111
- throw err;
112
- });
113
- });
114
- }
115
-
116
45
  /**
117
46
  * Sends a ROAP message
118
47
  * @param {Object} options
@@ -9,6 +9,12 @@ import RoapRequest from './request';
9
9
 
10
10
  const TURN_DISCOVERY_TIMEOUT = 10; // in seconds
11
11
 
12
+ // Roap spec says that seq should start from 1, but TURN discovery works fine with seq=0
13
+ // and this is handy for us, because TURN discovery is always done before the first SDP exchange,
14
+ // so we can do it with seq=0 or not do it at all and then we create the RoapMediaConnection
15
+ // and do the SDP offer with seq=1
16
+ const TURN_DISCOVERY_SEQ = 0;
17
+
12
18
  /**
13
19
  * Handles the process of finding out TURN server information from Linus.
14
20
  * This is achieved by sending a TURN_DISCOVERY_REQUEST.
@@ -126,8 +132,6 @@ export default class TurnDiscovery {
126
132
  * @memberof Roap
127
133
  */
128
134
  sendRoapTurnDiscoveryRequest(meeting, isReconnecting) {
129
- const seq = meeting.roapSeq + 1;
130
-
131
135
  if (this.defer) {
132
136
  LoggerProxy.logger.warn('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> already in progress');
133
137
 
@@ -139,7 +143,7 @@ export default class TurnDiscovery {
139
143
  const roapMessage = {
140
144
  messageType: ROAP.ROAP_TYPES.TURN_DISCOVERY_REQUEST,
141
145
  version: ROAP.ROAP_VERSION,
142
- seq,
146
+ seq: TURN_DISCOVERY_SEQ,
143
147
  };
144
148
 
145
149
  LoggerProxy.logger.info('Roap:turnDiscovery#sendRoapTurnDiscoveryRequest --> sending TURN_DISCOVERY_REQUEST');
@@ -155,8 +159,6 @@ export default class TurnDiscovery {
155
159
  meetingId: meeting.id
156
160
  })
157
161
  .then(({mediaConnections}) => {
158
- meeting.setRoapSeq(seq);
159
-
160
162
  if (mediaConnections) {
161
163
  meeting.updateMediaConnections(mediaConnections);
162
164
  }
@@ -177,7 +179,7 @@ export default class TurnDiscovery {
177
179
  roapMessage: {
178
180
  messageType: ROAP.ROAP_TYPES.OK,
179
181
  version: ROAP.ROAP_VERSION,
180
- seq: meeting.roapSeq
182
+ seq: TURN_DISCOVERY_SEQ,
181
183
  },
182
184
  locusSelfUrl: meeting.selfUrl,
183
185
  mediaId: meeting.mediaId,
@@ -196,6 +198,10 @@ export default class TurnDiscovery {
196
198
  * | <----TURN_DISCOVERY_RESPONSE----- |
197
199
  * | --------------OK----------------> |
198
200
  *
201
+ * This TURN discovery roap exchange is always done with seq=0.
202
+ * The RoapMediaConnection SDP exchange always starts with seq=1,
203
+ * so it works fine no matter if TURN discovery is done or not.
204
+ *
199
205
  * @param {Meeting} meeting
200
206
  * @param {Boolean} isReconnecting should be set to true if this is a new
201
207
  * media connection just after a reconnection
@@ -2,6 +2,7 @@ const STATS_DEFAULT = {
2
2
  encryption: 'sha-256',
3
3
  audio: {
4
4
  send: {
5
+ trackLabel: '',
5
6
  maxPacketLossRatio: 0,
6
7
  availableBandwidth: 0,
7
8
  bytesSent: 0,
@@ -17,6 +18,7 @@ const STATS_DEFAULT = {
17
18
  },
18
19
  video: {
19
20
  send: {
21
+ trackLabel: '',
20
22
  maxPacketLossRatio: 0,
21
23
  availableBandwidth: 0,
22
24
  meanRemoteJitter: [],