@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
@@ -7,15 +7,15 @@ import LoggerProxy from '../common/logs/logger-proxy';
7
7
  import {
8
8
  AUDIO_INPUT,
9
9
  VIDEO_INPUT,
10
- PEER_CONNECTION_STATE,
11
- MEDIA_TRACK_CONSTRAINT
10
+ MEDIA_TRACK_CONSTRAINT,
12
11
  } from '../constants';
13
12
  import Config from '../config';
14
- import PeerConnectionManager from '../peer-connection-manager';
15
- import ReconnectionError from '../common/errors/reconnection';
13
+ import StaticConfig from '../common/config';
16
14
  import MediaError from '../common/errors/media';
17
15
  import BrowserDetection from '../common/browser-detection';
18
16
 
17
+ import {RoapMediaConnection, MultistreamRoapMediaConnection} from './internal-media-core-wrapper';
18
+
19
19
  const {isBrowser} = BrowserDetection();
20
20
 
21
21
  /**
@@ -64,32 +64,6 @@ Media.setLocalTrack = (enabled, track) => {
64
64
  return false;
65
65
  };
66
66
 
67
- /**
68
- * @param {RTCPeerConnection} peerConnection
69
- * @param {Object} meetingProperties
70
- * @param {string} meetingProperties.meetingId
71
- * @param {string} meetingProperties.remoteQualityLevel LOW|MEDIUM|HIGH
72
- * @returns {Promise}
73
- */
74
- Media.reconnectMedia = (peerConnection, {
75
- meetingId,
76
- remoteQualityLevel,
77
- enableRtx,
78
- enableExtmap
79
- }) => {
80
- if (peerConnection.connectionState === PEER_CONNECTION_STATE.CLOSED ||
81
- peerConnection.connectionState === PEER_CONNECTION_STATE.FAILED) {
82
- return Promise.reject(new ReconnectionError('Reinitiate peerconnection'));
83
- }
84
-
85
- return PeerConnectionManager.createOffer(peerConnection, {
86
- meetingId,
87
- remoteQualityLevel,
88
- enableRtx,
89
- enableExtmap
90
- });
91
- };
92
-
93
67
  /**
94
68
  * format the media array for send
95
69
  * @param {String} mediaId
@@ -141,186 +115,78 @@ Media.getLocalMedia = (options, config) => {
141
115
 
142
116
  return Promise.resolve(undefined);
143
117
  };
144
- /**
145
- * Returns the direction and tracks
146
- * @param {string} trackType type of track (audio/video)
147
- * @param {object} track tracks passed
148
- * @param {boolean} receiveTracks do you want to receive tracks from the remote side
149
- * @returns {Object} returns direction tracks to be added in transceiver
150
- */
151
- Media.checkTracks = (trackType, track, receiveTracks) => {
152
- const getDirection = (sendTracks, receiveTracks) => {
153
- if (sendTracks && receiveTracks) {
154
- return 'sendrecv';
155
- } if (sendTracks && !receiveTracks) {
156
- return 'sendonly';
157
- } if (!sendTracks && receiveTracks) {
158
- return 'recvonly';
159
- }
160
-
161
- return 'inactive';
162
- };
163
-
164
- if (track) {
165
- return {track, direction: getDirection(!!track, receiveTracks)};
166
- }
167
-
168
- return {track: trackType, direction: getDirection(!!track, receiveTracks)};
169
- };
170
- /**
171
- * creates peerconnection and attaches streams
172
- * @param {MediaDirection} mediaProperties
173
- * @param {Object} meetingProperties
174
- * @param {string} meetingProperties.meetingId
175
- * @param {string} meetingProperties.remoteQualityLevel LOW|MEDIUM|HIGH
176
- * @returns {Array} [peerConnection, ]
177
- */
178
- Media.attachMedia = (mediaProperties, {
179
- meetingId,
180
- remoteQualityLevel,
181
- enableRtx,
182
- enableExtmap
183
- }) => {
184
- const {
185
- mediaDirection,
186
- audioTrack,
187
- videoTrack,
188
- shareTrack,
189
- peerConnection
190
- } = mediaProperties;
191
-
192
- let result = null;
193
-
194
- // Add Transceiver for audio
195
- result = Media.checkTracks('audio', mediaDirection.sendAudio && audioTrack, mediaDirection.receiveAudio);
196
- peerConnection.audioTransceiver = peerConnection.addTransceiver(result.track, {direction: result.direction});
197
-
198
- // Add Transceiver for video
199
- result = Media.checkTracks('video', mediaDirection.sendVideo && videoTrack, mediaDirection.receiveVideo);
200
- peerConnection.videoTransceiver = peerConnection.addTransceiver(result.track, {direction: result.direction});
201
-
202
- // Add Transceiver for share
203
- result = Media.checkTracks('video', mediaDirection.sendShare && shareTrack, mediaDirection.receiveShare);
204
- peerConnection.shareTransceiver = peerConnection.addTransceiver(result.track, {direction: result.direction});
205
-
206
- peerConnection.onnegotiationneeded = (event) => {
207
- LoggerProxy.logger.info(`Media:index#attachMedia --> onnegotiationneeded#PeerConnection: ${event}`);
208
- };
209
-
210
- return PeerConnectionManager.createOffer(peerConnection, {
211
- meetingId,
212
- remoteQualityLevel,
213
- enableRtx,
214
- enableExtmap
215
- });
216
- };
217
118
 
218
119
  /**
219
- * updates all the media streams and creates a new media offer
220
- * @param {MediaDirection} mediaProperties
221
- * @param {Object} meetingProperties
222
- * @param {string} meetingProperties.meetingId
223
- * @param {string} meetingProperties.remoteQualityLevel LOW|MEDIUM|HIGH
224
- * @returns {Promise}
120
+ * creates a webrtc media connection with provided tracks and mediaDirection configuration
121
+ * @param {Object} mediaProperties only applicable to non-multistream connections, contains mediaDirection and local tracks:
122
+ * audioTrack, videoTrack and shareTrack
123
+ * @param {Object} options
124
+ * @param {boolean} options.isMultistream
125
+ * @param {string} [options.remoteQualityLevel] LOW|MEDIUM|HIGH applicable only to non-multistream connections
126
+ * @param {boolean} [options.enableRtx] applicable only to non-multistream connections
127
+ * @param {boolean} [options.enableExtmap] applicable only to non-multistream connections
128
+ * @param {Object} [options.turnServerInfo]
129
+ * @returns {RoapMediaConnection}
225
130
  */
226
- Media.updateMedia = (mediaProperties, {
227
- meetingId,
131
+ Media.createMediaConnection = (mediaProperties, {
132
+ isMultistream,
228
133
  remoteQualityLevel,
229
134
  enableRtx,
230
- enableExtmap
135
+ enableExtmap,
136
+ turnServerInfo
231
137
  }) => {
232
138
  const {
233
139
  mediaDirection,
234
140
  audioTrack,
235
141
  videoTrack,
236
- shareTrack,
237
- peerConnection
142
+ shareTrack
238
143
  } = mediaProperties;
239
144
 
240
- // update audio transceiver
241
- Media.setTrackOnTransceiver(peerConnection.audioTransceiver, {
242
- type: 'audio',
243
- track: audioTrack,
244
- sendTrack: mediaDirection.sendAudio && audioTrack,
245
- receiveTrack: mediaDirection.receiveAudio
246
- });
247
-
248
- // update video transceiver
249
- Media.setTrackOnTransceiver(peerConnection.videoTransceiver, {
250
- type: 'video',
251
- track: videoTrack,
252
- sendTrack: mediaDirection.sendVideo && videoTrack,
253
- receiveTrack: mediaDirection.receiveVideo
254
- });
255
-
256
- // update content transceiver
257
- Media.setTrackOnTransceiver(peerConnection.shareTransceiver, {
258
- type: 'video',
259
- track: shareTrack,
260
- sendTrack: mediaDirection.sendShare && shareTrack,
261
- receiveTrack: mediaDirection.receiveShare
262
- });
263
- peerConnection.onnegotiationneeded = (event) => {
264
- LoggerProxy.logger.info(`Media:index#updateMedia --> onnegotiationneeded#PeerConnection: ${event}`);
265
- };
266
-
267
- return PeerConnectionManager.createOffer(peerConnection, {
268
- meetingId,
269
- remoteQualityLevel,
270
- enableRtx,
271
- enableExtmap
272
- });
273
- };
274
-
275
- /**
276
- * @param {RTCRtpTransceiver} transceiver
277
- * @param {Object} options
278
- * @param {MediaStreamTrack} options.track
279
- * @returns {undefined}
280
- */
281
- Media.setTrackOnTransceiver = (transceiver, options) => {
282
- const {
283
- type, track, sendTrack, receiveTrack
284
- } = options;
285
-
286
- try {
287
- const result = Media.checkTracks(type, sendTrack && track, receiveTrack);
145
+ const iceServers = [];
288
146
 
289
- transceiver.direction = result.direction;
290
- if (options.track) {
291
- transceiver.sender.replaceTrack(track);
292
- }
147
+ if (turnServerInfo) {
148
+ iceServers.push({
149
+ urls: turnServerInfo.url,
150
+ username: turnServerInfo.username || '',
151
+ credential: turnServerInfo.password || ''
152
+ });
293
153
  }
294
- catch (e) {
295
- LoggerProxy.logger.error(`Media:index#setTrackOnTransceiver --> ${e}`);
296
- throw e;
154
+
155
+ if (isMultistream) {
156
+ return new MultistreamRoapMediaConnection({
157
+ iceServers,
158
+ }, 'mc');
297
159
  }
298
- };
299
160
 
300
- /**
301
- * creates a new offer
302
- * @param {Object} meetingProperties
303
- * @param {string} meetingProperties.meetingId
304
- * @param {string} meetingProperties.remoteQualityLevel LOW|MEDIUM|HIGH
305
- * @param {RTCPeerConnection} peerConnection
306
- * @param {RTCRtpTransceiver} transceiver
307
- * @param {Object} options see #Media.setTrackOnTransceiver
308
- * @returns {Promise}
309
- */
310
- Media.updateTransceiver = ({
311
- meetingId,
312
- remoteQualityLevel,
313
- enableRtx,
314
- enableExtmap
315
- }, peerConnection, transceiver, options) => {
316
- Media.setTrackOnTransceiver(transceiver, options);
317
-
318
- return PeerConnectionManager.createOffer(peerConnection, {
319
- meetingId,
320
- remoteQualityLevel,
321
- enableRtx,
322
- enableExtmap
323
- });
161
+ return new RoapMediaConnection({
162
+ iceServers,
163
+ skipInactiveTransceivers: false,
164
+ requireH264: true,
165
+ sdpMunging: {
166
+ convertPort9to0: false,
167
+ addContentSlides: true,
168
+ bandwidthLimits: {
169
+ audio: StaticConfig.meetings.bandwidth.audio,
170
+ video: StaticConfig.meetings.bandwidth.video,
171
+ },
172
+ startBitrate: StaticConfig.meetings.bandwidth.startBitrate,
173
+ periodicKeyframes: 20, // it's always been hardcoded in SDK so for now keeping it that way
174
+ disableExtmap: !enableExtmap,
175
+ disableRtx: !enableRtx, // see https://bugs.chromium.org/p/chromium/issues/detail?id=1020642 why we might want to remove RTX from SDP
176
+ }
177
+ }, {
178
+ send: {
179
+ audio: audioTrack,
180
+ video: videoTrack,
181
+ screenShareVideo: shareTrack
182
+ },
183
+ receive: {
184
+ audio: mediaDirection.receiveAudio,
185
+ video: mediaDirection.receiveVideo,
186
+ screenShareVideo: mediaDirection.receiveShare,
187
+ remoteQualityLevel
188
+ }
189
+ }, 'mc');
324
190
  };
325
191
 
326
192
  /**
@@ -0,0 +1,9 @@
1
+ import {MediaConnection as MC} from '@webex/internal-media-core';
2
+
3
+ /* We have this wrapper just because otherwise it's impossible to mock
4
+ * RoapMediaConnection and MultistreamRoapMediaConnection constructors in unit tests,
5
+ * because they are exported by @webex/internal-media-core as non-writable, non-configurable
6
+ * properties of MediaConnection and sinon doesn't allow spying on them or stubbing them.
7
+ */
8
+ export const RoapMediaConnection = MC.RoapMediaConnection;
9
+ export const MultistreamRoapMediaConnection = MC.MultistreamRoapMediaConnection;
@@ -1,13 +1,12 @@
1
+ import {MediaConnection as MC} from '@webex/internal-media-core';
2
+
1
3
  import {
2
- ICE_STATE,
3
4
  MEETINGS,
4
5
  PC_BAIL_TIMEOUT,
5
6
  QUALITY_LEVELS
6
7
  } from '../constants';
7
8
  import LoggerProxy from '../common/logs/logger-proxy';
8
9
 
9
- import MediaUtil from './util';
10
-
11
10
  /**
12
11
  * @class MediaProperties
13
12
  */
@@ -19,7 +18,7 @@ export default class MediaProperties {
19
18
  * @returns {MediaProperties}
20
19
  */
21
20
  constructor(options = {}) {
22
- this.peerConnection = MediaUtil.createPeerConnection();
21
+ this.webrtcMediaConnection = null;
23
22
  this.mediaDirection = options.mediaDirection;
24
23
  this.videoTrack = options.videoTrack;
25
24
  this.audioTrack = options.audioTrack;
@@ -49,8 +48,8 @@ export default class MediaProperties {
49
48
  this.mediaSettings[type] = values;
50
49
  }
51
50
 
52
- setMediaPeerConnection(peerConnection) {
53
- this.peerConnection = peerConnection;
51
+ setMediaPeerConnection(mediaPeerConnection) {
52
+ this.webrtcMediaConnection = mediaPeerConnection;
54
53
  }
55
54
 
56
55
  setLocalVideoTrack(videoTrack) {
@@ -105,11 +104,7 @@ export default class MediaProperties {
105
104
  }
106
105
 
107
106
  unsetPeerConnection() {
108
- this.peerConnection = null;
109
- }
110
-
111
- reInitiatePeerconnection(turnServerInfo) {
112
- this.peerConnection = MediaUtil.createPeerConnection(turnServerInfo);
107
+ this.webrtcMediaConnection = null;
113
108
  }
114
109
 
115
110
  unsetLocalVideoTrack() {
@@ -199,39 +194,38 @@ export default class MediaProperties {
199
194
  }
200
195
 
201
196
  /**
202
- * Waits until ice connection is established
197
+ * Waits for the webrtc media connection to be connected.
203
198
  *
204
199
  * @returns {Promise<void>}
205
200
  */
206
- waitForIceConnectedState() {
207
- const isIceConnected = () => (
208
- this.peerConnection.iceConnectionState === ICE_STATE.CONNECTED ||
209
- this.peerConnection.iceConnectionState === ICE_STATE.COMPLETED
201
+ waitForMediaConnectionConnected() {
202
+ const isConnected = () => (
203
+ this.webrtcMediaConnection.getConnectionState() === MC.ConnectionState.Connected
210
204
  );
211
205
 
212
- if (isIceConnected()) {
206
+ if (isConnected()) {
213
207
  return Promise.resolve();
214
208
  }
215
209
 
216
210
  return new Promise((resolve, reject) => {
217
211
  let timer;
218
212
 
219
- const iceListener = () => {
220
- LoggerProxy.logger.log(`Media:properties#waitForIceConnectedState --> ice state: ${this.peerConnection.iceConnectionState}, conn state: ${this.peerConnection.connectionState}`);
213
+ const connectionStateListener = () => {
214
+ LoggerProxy.logger.log(`Media:properties#waitForMediaConnectionConnected --> connection state: ${this.webrtcMediaConnection.getConnectionState()}`);
221
215
 
222
- if (isIceConnected()) {
216
+ if (isConnected()) {
223
217
  clearTimeout(timer);
224
- this.peerConnection.removeEventListener('iceconnectionstatechange', iceListener);
218
+ this.webrtcMediaConnection.off(MC.Event.CONNECTION_STATE_CHANGED, connectionStateListener);
225
219
  resolve();
226
220
  }
227
221
  };
228
222
 
229
223
  timer = setTimeout(() => {
230
- this.peerConnection.removeEventListener('iceconnectionstatechange', iceListener);
224
+ this.webrtcMediaConnection.off(MC.Event.CONNECTION_STATE_CHANGED, connectionStateListener);
231
225
  reject();
232
226
  }, PC_BAIL_TIMEOUT);
233
227
 
234
- this.peerConnection.addEventListener('iceconnectionstatechange', iceListener);
228
+ this.webrtcMediaConnection.on(MC.Event.CONNECTION_STATE_CHANGED, connectionStateListener);
235
229
  });
236
230
  }
237
231
 
@@ -242,13 +236,13 @@ export default class MediaProperties {
242
236
  */
243
237
  async getCurrentConnectionType() {
244
238
  // we can only get the connection type after ICE connection has been established
245
- await this.waitForIceConnectedState();
239
+ await this.waitForMediaConnectionConnected();
246
240
 
247
241
  const allStatsReports = [];
248
242
 
249
243
  try {
250
244
  // eslint-disable-next-line no-await-in-loop
251
- const statsResult = await this.peerConnection.getStats();
245
+ const statsResult = await this.webrtcMediaConnection.getStats();
252
246
 
253
247
  statsResult.forEach((report) => allStatsReports.push(report));
254
248
  }
package/src/media/util.js CHANGED
@@ -1,31 +1,9 @@
1
1
  /* globals MediaStream */
2
- import window from 'global/window';
3
2
 
4
- import BrowserDetection from '../common/browser-detection';
5
3
  import LoggerProxy from '../common/logs/logger-proxy';
6
4
 
7
- const {isBrowser} = BrowserDetection();
8
-
9
5
  const MediaUtil = {};
10
6
 
11
- MediaUtil.createPeerConnection = (turnServerInfo) => {
12
- const config = {iceServers: []};
13
-
14
- if (turnServerInfo) {
15
- config.iceServers.push({
16
- urls: turnServerInfo.url,
17
- username: turnServerInfo.username || '',
18
- credential: turnServerInfo.password || ''
19
- });
20
- }
21
- if (isBrowser('firefox')) {
22
- config.bundlePolicy = 'max-compat';
23
- }
24
-
25
- return new window.RTCPeerConnection(config);
26
- };
27
-
28
-
29
7
  MediaUtil.createMediaStream = (tracks) => {
30
8
  if (!tracks) {
31
9
  LoggerProxy.logger.error('Media:util#createMediaStream --> Tracks don\'t exist');