Procházet zdrojové kódy

Merge pull request #372 from jitsi/move_jingle_session

Move JingleSessionPC from ChatRoom to JitsiConference
dev1
Paweł Domas před 8 roky
rodič
revize
77ada51d1e

+ 125
- 38
JitsiConference.js Zobrazit soubor

34
  * @constructor
34
  * @constructor
35
  */
35
  */
36
 function JitsiConference(options) {
36
 function JitsiConference(options) {
37
-    if(!options.name || options.name.toLowerCase() !== options.name) {
37
+    if (!options.name || options.name.toLowerCase() !== options.name) {
38
         var errmsg
38
         var errmsg
39
             = "Invalid conference name (no conference name passed or it "
39
             = "Invalid conference name (no conference name passed or it "
40
                 + "contains invalid characters like capital letters)!";
40
                 + "contains invalid characters like capital letters)!";
47
     this._init(options);
47
     this._init(options);
48
     this.componentsVersions = new ComponentsVersions(this);
48
     this.componentsVersions = new ComponentsVersions(this);
49
     this.participants = {};
49
     this.participants = {};
50
+    /**
51
+     * Jingle Session instance
52
+     * @type {JingleSessionPC}
53
+     */
54
+    this.jingleSession = null;
50
     this.lastDominantSpeaker = null;
55
     this.lastDominantSpeaker = null;
51
     this.dtmfManager = null;
56
     this.dtmfManager = null;
52
     this.somebodySupportsDTMF = false;
57
     this.somebodySupportsDTMF = false;
87
  * @param connection {JitsiConnection} overrides this.connection
92
  * @param connection {JitsiConnection} overrides this.connection
88
  */
93
  */
89
 JitsiConference.prototype._init = function (options) {
94
 JitsiConference.prototype._init = function (options) {
90
-    if(!options)
95
+    if (!options)
91
         options = {};
96
         options = {};
92
 
97
 
93
     // Override connection and xmpp properties (Usefull if the connection
98
     // Override connection and xmpp properties (Usefull if the connection
94
     // reloaded)
99
     // reloaded)
95
-    if(options.connection) {
100
+    if (options.connection) {
96
         this.connection = options.connection;
101
         this.connection = options.connection;
97
         this.xmpp = this.connection.xmpp;
102
         this.xmpp = this.connection.xmpp;
98
         // Setup XMPP events only if we have new connection object.
103
         // Setup XMPP events only if we have new connection object.
103
 
108
 
104
     this.room.updateDeviceAvailability(RTC.getDeviceAvailability());
109
     this.room.updateDeviceAvailability(RTC.getDeviceAvailability());
105
 
110
 
106
-    if(!this.rtc) {
111
+    if (!this.rtc) {
107
         this.rtc = new RTC(this, options);
112
         this.rtc = new RTC(this, options);
108
         this.eventManager.setupRTCListeners();
113
         this.eventManager.setupRTCListeners();
109
     }
114
     }
114
                 options.config.peerDisconnectedThroughRtcTimeout);
119
                 options.config.peerDisconnectedThroughRtcTimeout);
115
     this.participantConnectionStatus.init();
120
     this.participantConnectionStatus.init();
116
 
121
 
117
-    if(!this.statistics) {
122
+    if (!this.statistics) {
118
         this.statistics = new Statistics(this.xmpp, {
123
         this.statistics = new Statistics(this.xmpp, {
119
             callStatsID: this.options.config.callStatsID,
124
             callStatsID: this.options.config.callStatsID,
120
             callStatsSecret: this.options.config.callStatsSecret,
125
             callStatsSecret: this.options.config.callStatsSecret,
144
  * @param password {string} the password
149
  * @param password {string} the password
145
  */
150
  */
146
 JitsiConference.prototype.join = function (password) {
151
 JitsiConference.prototype.join = function (password) {
147
-    if(this.room)
152
+    if (this.room)
148
         this.room.join(password);
153
         this.room.join(password);
149
 };
154
 };
150
 
155
 
168
     this.getLocalTracks().forEach(track => this.onTrackRemoved(track));
173
     this.getLocalTracks().forEach(track => this.onTrackRemoved(track));
169
 
174
 
170
     this.rtc.closeAllDataChannels();
175
     this.rtc.closeAllDataChannels();
171
-    if(this.statistics)
176
+    if (this.statistics)
172
         this.statistics.dispose();
177
         this.statistics.dispose();
173
 
178
 
174
     // leave the conference
179
     // leave the conference
181
             // ChatRoom instance.
186
             // ChatRoom instance.
182
             this.getParticipants().forEach(
187
             this.getParticipants().forEach(
183
                 participant => this.onMemberLeft(participant.getJid()));
188
                 participant => this.onMemberLeft(participant.getJid()));
189
+            // Close the JingleSession
190
+            if (this.jingleSession) {
191
+                this.jingleSession.close();
192
+                this.jingleSession = null;
193
+            }
184
         });
194
         });
185
     }
195
     }
186
 
196
 
272
  * Note: consider adding eventing functionality by extending an EventEmitter impl, instead of rolling ourselves
282
  * Note: consider adding eventing functionality by extending an EventEmitter impl, instead of rolling ourselves
273
  */
283
  */
274
 JitsiConference.prototype.on = function (eventId, handler) {
284
 JitsiConference.prototype.on = function (eventId, handler) {
275
-    if(this.eventEmitter)
285
+    if (this.eventEmitter)
276
         this.eventEmitter.on(eventId, handler);
286
         this.eventEmitter.on(eventId, handler);
277
 };
287
 };
278
 
288
 
284
  * Note: consider adding eventing functionality by extending an EventEmitter impl, instead of rolling ourselves
294
  * Note: consider adding eventing functionality by extending an EventEmitter impl, instead of rolling ourselves
285
  */
295
  */
286
 JitsiConference.prototype.off = function (eventId, handler) {
296
 JitsiConference.prototype.off = function (eventId, handler) {
287
-    if(this.eventEmitter)
297
+    if (this.eventEmitter)
288
         this.eventEmitter.removeListener(eventId, handler);
298
         this.eventEmitter.removeListener(eventId, handler);
289
 };
299
 };
290
 
300
 
299
  * @param handler {Function} handler for the command
309
  * @param handler {Function} handler for the command
300
  */
310
  */
301
  JitsiConference.prototype.addCommandListener = function (command, handler) {
311
  JitsiConference.prototype.addCommandListener = function (command, handler) {
302
-    if(this.room)
312
+    if (this.room)
303
         this.room.addPresenceListener(command, handler);
313
         this.room.addPresenceListener(command, handler);
304
  };
314
  };
305
 
315
 
308
   * @param command {String} the name of the command
318
   * @param command {String} the name of the command
309
   */
319
   */
310
  JitsiConference.prototype.removeCommandListener = function (command) {
320
  JitsiConference.prototype.removeCommandListener = function (command) {
311
-    if(this.room)
321
+    if (this.room)
312
         this.room.removePresenceListener(command);
322
         this.room.removePresenceListener(command);
313
  };
323
  };
314
 
324
 
317
  * @param message the text message.
327
  * @param message the text message.
318
  */
328
  */
319
 JitsiConference.prototype.sendTextMessage = function (message) {
329
 JitsiConference.prototype.sendTextMessage = function (message) {
320
-    if(this.room)
330
+    if (this.room)
321
         this.room.sendMessage(message);
331
         this.room.sendMessage(message);
322
 };
332
 };
323
 
333
 
327
  * @param values {Object} with keys and values that will be sent.
337
  * @param values {Object} with keys and values that will be sent.
328
  **/
338
  **/
329
 JitsiConference.prototype.sendCommand = function (name, values) {
339
 JitsiConference.prototype.sendCommand = function (name, values) {
330
-    if(this.room) {
340
+    if (this.room) {
331
         this.room.addToPresence(name, values);
341
         this.room.addToPresence(name, values);
332
         this.room.sendPresence();
342
         this.room.sendPresence();
333
     }
343
     }
348
  * @param name {String} the name of the command.
358
  * @param name {String} the name of the command.
349
  **/
359
  **/
350
 JitsiConference.prototype.removeCommand = function (name) {
360
 JitsiConference.prototype.removeCommand = function (name) {
351
-    if(this.room)
361
+    if (this.room)
352
         this.room.removeFromPresence(name);
362
         this.room.removeFromPresence(name);
353
 };
363
 };
354
 
364
 
357
  * @param name the display name to set
367
  * @param name the display name to set
358
  */
368
  */
359
 JitsiConference.prototype.setDisplayName = function(name) {
369
 JitsiConference.prototype.setDisplayName = function(name) {
360
-    if(this.room){
370
+    if (this.room){
361
         // remove previously set nickname
371
         // remove previously set nickname
362
         this.room.removeFromPresence("nick");
372
         this.room.removeFromPresence("nick");
363
 
373
 
381
  * @return {Transcriber} the transcriber object
391
  * @return {Transcriber} the transcriber object
382
  */
392
  */
383
 JitsiConference.prototype.getTranscriber = function(){
393
 JitsiConference.prototype.getTranscriber = function(){
384
-    if(this.transcriber === undefined){
394
+    if (this.transcriber === undefined){
385
         this.transcriber = new Transcriber();
395
         this.transcriber = new Transcriber();
386
         //add all existing local audio tracks to the transcriber
396
         //add all existing local audio tracks to the transcriber
387
         this.rtc.localTracks.forEach(function (localTrack) {
397
         this.rtc.localTracks.forEach(function (localTrack) {
388
-            if(localTrack.isAudioTrack()){
398
+            if (localTrack.isAudioTrack()){
389
                 this.transcriber.addTrack(localTrack);
399
                 this.transcriber.addTrack(localTrack);
390
             }
400
             }
391
         }.bind(this));
401
         }.bind(this));
392
         //and all remote audio tracks
402
         //and all remote audio tracks
393
         this.rtc.remoteTracks.forEach(function (remoteTrack){
403
         this.rtc.remoteTracks.forEach(function (remoteTrack){
394
-            if(remoteTrack.isAudioTrack()){
404
+            if (remoteTrack.isAudioTrack()){
395
                 this.transcriber.addTrack(remoteTrack);
405
                 this.transcriber.addTrack(remoteTrack);
396
             }
406
             }
397
         }.bind(this));
407
         }.bind(this));
476
 /**
486
 /**
477
  * Removes JitsiLocalTrack from the conference and performs
487
  * Removes JitsiLocalTrack from the conference and performs
478
  * a new offer/answer cycle.
488
  * a new offer/answer cycle.
479
- * @param track the JitsiLocalTrack object.
489
+ * @param {JitsiLocalTrack} track
480
  * @returns {Promise}
490
  * @returns {Promise}
481
  */
491
  */
482
 JitsiConference.prototype.removeTrack = function (track) {
492
 JitsiConference.prototype.removeTrack = function (track) {
517
             newTrack.ssrcHandler);
527
             newTrack.ssrcHandler);
518
     }
528
     }
519
     // Now replace the stream at the lower levels
529
     // Now replace the stream at the lower levels
520
-    return this.room.replaceStream (oldTrack, newTrack)
530
+    return this._doReplaceTrack(oldTrack, newTrack)
521
         .then(() => {
531
         .then(() => {
522
             if (oldTrack) {
532
             if (oldTrack) {
523
                 this.onTrackRemoved(oldTrack);
533
                 this.onTrackRemoved(oldTrack);
532
         });
542
         });
533
 };
543
 };
534
 
544
 
545
+/**
546
+ * Replaces the tracks at the lower level by going through the Jingle session
547
+ * and WebRTC peer connection. The method will resolve immediately if there is
548
+ * currently no JingleSession started.
549
+ * @param {JitsiLocalTrack|null} oldTrack the track to be removed during
550
+ * the process or <tt>null</t> if the method should act as "add track"
551
+ * @param {JitsiLocalTrack|null} newTrack the new track to be added or
552
+ * <tt>null</tt> if the method should act as "remove track"
553
+ * @return {Promise}
554
+ * @private
555
+ */
556
+JitsiConference.prototype._doReplaceTrack = function (oldTrack, newTrack) {
557
+    if (this.jingleSession) {
558
+        return this.jingleSession.replaceTrack(oldTrack, newTrack);
559
+    } else {
560
+        return Promise.resolve();
561
+    }
562
+};
563
+
535
 /**
564
 /**
536
  * Operations related to creating a new track
565
  * Operations related to creating a new track
537
  * @param {JitsiLocalTrack} newTrack the new track being created
566
  * @param {JitsiLocalTrack} newTrack the new track being created
590
     this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, newTrack);
619
     this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, newTrack);
591
 };
620
 };
592
 
621
 
622
+/**
623
+ * Adds loca WebRTC stream to the conference.
624
+ * @param {MediaStream} stream new stream that will be added.
625
+ * @param {function} callback callback executed after successful stream addition.
626
+ * @param {function(error)} errorCallback callback executed if stream addition fail.
627
+ * @param {object} ssrcInfo object with information about the SSRCs associated with the
628
+ * stream.
629
+ * @param {boolean} [dontModifySources] if <tt>true</tt> _modifySources won't be
630
+ * called. The option is used for adding stream, before the Jingle call is
631
+ * started. That is before the 'session-accept' is sent.
632
+ */
633
+JitsiConference.prototype._addLocalStream
634
+    = function (stream, callback, errorCallback, ssrcInfo, dontModifySources) {
635
+    if (this.jingleSession) {
636
+        this.jingleSession.addStream(
637
+            stream, callback, errorCallback, ssrcInfo, dontModifySources);
638
+    } else {
639
+        // We are done immediately
640
+        logger.warn("Add local MediaStream - no JingleSession started yet");
641
+        callback();
642
+    }
643
+};
644
+
645
+/**
646
+ * Remove local WebRTC media stream.
647
+ * @param {MediaStream} stream the stream that will be removed.
648
+ * @param {function} callback callback executed after successful stream removal.
649
+ * @param {function} errorCallback callback executed if stream removal fail.
650
+ * @param {object} ssrcInfo object with information about the SSRCs associated
651
+ * with the stream.
652
+ */
653
+JitsiConference.prototype.removeLocalStream
654
+    = function (stream, callback, errorCallback, ssrcInfo) {
655
+    if (this.jingleSession) {
656
+        this.jingleSession.removeStream(
657
+            stream, callback, errorCallback, ssrcInfo);
658
+    } else {
659
+        // We are done immediately
660
+        logger.warn("Remove local MediaStream - no JingleSession started yet");
661
+        callback();
662
+    }
663
+};
664
+
665
+/**
666
+ * Generate ssrc info object for a stream with the following properties:
667
+ * - ssrcs - Array of the ssrcs associated with the stream.
668
+ * - groups - Array of the groups associated with the stream.
669
+ */
670
+JitsiConference.prototype._generateNewStreamSSRCInfo = function () {
671
+    if (!this.jingleSession) {
672
+        logger.warn("The call haven't been started. " +
673
+            "Cannot generate ssrc info at the moment!");
674
+        return null;
675
+    }
676
+    return this.jingleSession.generateNewStreamSSRCInfo();
677
+};
678
+
593
 /**
679
 /**
594
  * Get role of the local user.
680
  * Get role of the local user.
595
  * @returns {string} user role: 'moderator' or 'none'
681
  * @returns {string} user role: 'moderator' or 'none'
825
     // Add track to JitsiParticipant.
911
     // Add track to JitsiParticipant.
826
     participant._tracks.push(track);
912
     participant._tracks.push(track);
827
 
913
 
828
-    if(this.transcriber){
914
+    if (this.transcriber){
829
         this.transcriber.addTrack(track);
915
         this.transcriber.addTrack(track);
830
     }
916
     }
831
 
917
 
875
     }
961
     }
876
 
962
 
877
     // Accept incoming call
963
     // Accept incoming call
878
-    this.room.setJingleSession(jingleSession);
964
+    this.jingleSession = jingleSession;
879
     this.room.connectionTimes["session.initiate"] = now;
965
     this.room.connectionTimes["session.initiate"] = now;
880
     // Log "session.restart"
966
     // Log "session.restart"
881
     if (this.wasStopped) {
967
     if (this.wasStopped) {
911
          *  problems between sdp-interop and trying to keep the ssrcs
997
          *  problems between sdp-interop and trying to keep the ssrcs
912
          *  consistent
998
          *  consistent
913
          */
999
          */
914
-        if(localTrack.isVideoTrack() && localTrack.isMuted() && !RTCBrowserType.isFirefox()) {
1000
+        if (localTrack.isVideoTrack() && localTrack.isMuted() && !RTCBrowserType.isFirefox()) {
915
             /**
1001
             /**
916
              * Handles issues when the stream is added before the peerconnection
1002
              * Handles issues when the stream is added before the peerconnection
917
              * is created. The peerconnection is created when second participant
1003
              * is created. The peerconnection is created when second participant
927
              * In order to solve issues like the above one here we have to
1013
              * In order to solve issues like the above one here we have to
928
              * generate the ssrc information for the track .
1014
              * generate the ssrc information for the track .
929
              */
1015
              */
930
-            localTrack._setSSRC(
931
-                this.room.generateNewStreamSSRCInfo());
1016
+            localTrack._setSSRC(this._generateNewStreamSSRCInfo());
932
             ssrcInfo = {
1017
             ssrcInfo = {
933
                 mtype: localTrack.getType(),
1018
                 mtype: localTrack.getType(),
934
                 type: "addMuted",
1019
                 type: "addMuted",
937
             };
1022
             };
938
         }
1023
         }
939
         try {
1024
         try {
940
-            this.room.addStream(
1025
+            this._addLocalStream(
941
                 localTrack.getOriginalStream(), function () {}, function () {},
1026
                 localTrack.getOriginalStream(), function () {}, function () {},
942
-                ssrcInfo, true);
1027
+                ssrcInfo, true /* don't modify SSRCs */);
943
         } catch(e) {
1028
         } catch(e) {
944
             GlobalOnErrorHandler.callErrorHandler(e);
1029
             GlobalOnErrorHandler.callErrorHandler(e);
945
             logger.error(e);
1030
             logger.error(e);
986
         this.statistics.stopCallStats();
1071
         this.statistics.stopCallStats();
987
     }
1072
     }
988
     // Current JingleSession is invalid so set it to null on the room
1073
     // Current JingleSession is invalid so set it to null on the room
989
-    this.room.setJingleSession(null);
1074
+    this.jingleSession = null;
990
     // Let the RTC service do any cleanups
1075
     // Let the RTC service do any cleanups
991
     this.rtc.onCallEnded();
1076
     this.rtc.onCallEnded();
992
     // PeerConnection has been closed which means that SSRCs stored in
1077
     // PeerConnection has been closed which means that SSRCs stored in
1073
  * Returns true if recording is supported and false if not.
1158
  * Returns true if recording is supported and false if not.
1074
  */
1159
  */
1075
 JitsiConference.prototype.isRecordingSupported = function () {
1160
 JitsiConference.prototype.isRecordingSupported = function () {
1076
-    if(this.room)
1161
+    if (this.room)
1077
         return this.room.isRecordingSupported();
1162
         return this.room.isRecordingSupported();
1078
     return false;
1163
     return false;
1079
 };
1164
 };
1097
  * Starts/stops the recording
1182
  * Starts/stops the recording
1098
  */
1183
  */
1099
 JitsiConference.prototype.toggleRecording = function (options) {
1184
 JitsiConference.prototype.toggleRecording = function (options) {
1100
-    if(this.room)
1185
+    if (this.room)
1101
         return this.room.toggleRecording(options, function (status, error) {
1186
         return this.room.toggleRecording(options, function (status, error) {
1102
             this.eventEmitter.emit(
1187
             this.eventEmitter.emit(
1103
                 JitsiConferenceEvents.RECORDER_STATE_CHANGED, status, error);
1188
                 JitsiConferenceEvents.RECORDER_STATE_CHANGED, status, error);
1111
  * Returns true if the SIP calls are supported and false otherwise
1196
  * Returns true if the SIP calls are supported and false otherwise
1112
  */
1197
  */
1113
 JitsiConference.prototype.isSIPCallingSupported = function () {
1198
 JitsiConference.prototype.isSIPCallingSupported = function () {
1114
-    if(this.room)
1199
+    if (this.room)
1115
         return this.room.isSIPCallingSupported();
1200
         return this.room.isSIPCallingSupported();
1116
     return false;
1201
     return false;
1117
 };
1202
 };
1121
  * @param number the number
1206
  * @param number the number
1122
  */
1207
  */
1123
 JitsiConference.prototype.dial = function (number) {
1208
 JitsiConference.prototype.dial = function (number) {
1124
-    if(this.room)
1209
+    if (this.room)
1125
         return this.room.dial(number);
1210
         return this.room.dial(number);
1126
     return new Promise(function(resolve, reject){
1211
     return new Promise(function(resolve, reject){
1127
         reject(new Error("The conference is not created yet!"));});
1212
         reject(new Error("The conference is not created yet!"));});
1131
  * Hangup an existing call
1216
  * Hangup an existing call
1132
  */
1217
  */
1133
 JitsiConference.prototype.hangup = function () {
1218
 JitsiConference.prototype.hangup = function () {
1134
-    if(this.room)
1219
+    if (this.room)
1135
         return this.room.hangup();
1220
         return this.room.hangup();
1136
     return new Promise(function(resolve, reject){
1221
     return new Promise(function(resolve, reject){
1137
         reject(new Error("The conference is not created yet!"));});
1222
         reject(new Error("The conference is not created yet!"));});
1141
  * Returns the phone number for joining the conference.
1226
  * Returns the phone number for joining the conference.
1142
  */
1227
  */
1143
 JitsiConference.prototype.getPhoneNumber = function () {
1228
 JitsiConference.prototype.getPhoneNumber = function () {
1144
-    if(this.room)
1229
+    if (this.room)
1145
         return this.room.getPhoneNumber();
1230
         return this.room.getPhoneNumber();
1146
     return null;
1231
     return null;
1147
 };
1232
 };
1150
  * Returns the pin for joining the conference with phone.
1235
  * Returns the pin for joining the conference with phone.
1151
  */
1236
  */
1152
 JitsiConference.prototype.getPhonePin = function () {
1237
 JitsiConference.prototype.getPhonePin = function () {
1153
-    if(this.room)
1238
+    if (this.room)
1154
         return this.room.getPhonePin();
1239
         return this.room.getPhonePin();
1155
     return null;
1240
     return null;
1156
 };
1241
 };
1160
  * for its session.
1245
  * for its session.
1161
  */
1246
  */
1162
 JitsiConference.prototype.getConnectionState = function () {
1247
 JitsiConference.prototype.getConnectionState = function () {
1163
-    if(this.room)
1164
-        return this.room.getConnectionState();
1165
-    return null;
1248
+    if (this.jingleSession) {
1249
+        return this.jingleSession.getIceConnectionState();
1250
+    } else {
1251
+        return null;
1252
+    }
1166
 };
1253
 };
1167
 
1254
 
1168
 /**
1255
 /**

+ 4
- 4
modules/RTC/JitsiLocalTrack.js Zobrazit soubor

363
  * @returns {Promise}
363
  * @returns {Promise}
364
  */
364
  */
365
 JitsiLocalTrack.prototype._addStreamToConferenceAsUnmute = function () {
365
 JitsiLocalTrack.prototype._addStreamToConferenceAsUnmute = function () {
366
-    if (!this.conference || !this.conference.room) {
366
+    if (!this.conference) {
367
         return Promise.resolve();
367
         return Promise.resolve();
368
     }
368
     }
369
 
369
 
370
     var self = this;
370
     var self = this;
371
 
371
 
372
     return new Promise(function(resolve, reject) {
372
     return new Promise(function(resolve, reject) {
373
-        self.conference.room.addStream(
373
+        self.conference._addLocalStream(
374
             self.stream,
374
             self.stream,
375
             resolve,
375
             resolve,
376
             (error) => reject(new Error(error)),
376
             (error) => reject(new Error(error)),
391
  */
391
  */
392
 JitsiLocalTrack.prototype._removeStreamFromConferenceAsMute =
392
 JitsiLocalTrack.prototype._removeStreamFromConferenceAsMute =
393
 function (successCallback, errorCallback) {
393
 function (successCallback, errorCallback) {
394
-    if (!this.conference || !this.conference.room) {
394
+    if (!this.conference) {
395
         successCallback();
395
         successCallback();
396
         return;
396
         return;
397
     }
397
     }
398
 
398
 
399
-    this.conference.room.removeStream(
399
+    this.conference.removeLocalStream(
400
         this.stream,
400
         this.stream,
401
         successCallback,
401
         successCallback,
402
         (error) => errorCallback(new Error(error)),
402
         (error) => errorCallback(new Error(error)),

+ 0
- 92
modules/xmpp/ChatRoom.js Zobrazit soubor

81
         this.moderator = new Moderator(this.roomjid, this.xmpp, this.eventEmitter,
81
         this.moderator = new Moderator(this.roomjid, this.xmpp, this.eventEmitter,
82
             {connection: this.xmpp.options, conference: this.options});
82
             {connection: this.xmpp.options, conference: this.options});
83
         this.initPresenceMap();
83
         this.initPresenceMap();
84
-        this.session = null;
85
         this.lastPresences = {};
84
         this.lastPresences = {};
86
         this.phoneNumber = null;
85
         this.phoneNumber = null;
87
         this.phonePin = null;
86
         this.phonePin = null;
705
         return null;
704
         return null;
706
     }
705
     }
707
 
706
 
708
-    setJingleSession (session){
709
-        this.session = session;
710
-    }
711
-
712
-    /**
713
-     * Replaces oldStream with newStream and performs a single offer/answer
714
-     *  cycle after both operations are done.  Either oldStream or newStream
715
-     *  can be null; replacing a valid 'oldStream' with a null 'newStream'
716
-     *  effectively just removes 'oldStream'
717
-     * @param oldStream the current stream in use to be replaced
718
-     * @param newStream the new stream to use
719
-     * @returns {Promise}
720
-     */
721
-    replaceStream (oldStream, newStream) {
722
-        if (this.session) {
723
-            return this.session.replaceStream(oldStream, newStream);
724
-        }
725
-        return Promise.resolve();
726
-    }
727
-
728
-    /**
729
-     * Remove stream.
730
-     * @param stream stream that will be removed.
731
-     * @param callback callback executed after successful stream removal.
732
-     * @param errorCallback callback executed if stream removal fail.
733
-     * @param ssrcInfo object with information about the SSRCs associated with the
734
-     * stream.
735
-     */
736
-    removeStream (stream, callback, errorCallback, ssrcInfo) {
737
-        if(!this.session) {
738
-            callback();
739
-            return;
740
-        }
741
-        this.session.removeStream(stream, callback, errorCallback, ssrcInfo);
742
-    }
743
-
744
-    /**
745
-     * Adds stream.
746
-     * @param stream new stream that will be added.
747
-     * @param callback callback executed after successful stream addition.
748
-     * @param errorCallback callback executed if stream addition fail.
749
-     * @param ssrcInfo object with information about the SSRCs associated with the
750
-     * stream.
751
-     * @param dontModifySources {boolean} if true _modifySources won't be called.
752
-     * Used for streams added before the call start.
753
-     */
754
-    addStream (stream, callback, errorCallback, ssrcInfo, dontModifySources) {
755
-        if(this.session) {
756
-            // FIXME: will block switchInProgress on true value in case of exception
757
-            this.session.addStream(stream, callback, errorCallback, ssrcInfo,
758
-                dontModifySources);
759
-        } else {
760
-            // We are done immediately
761
-            logger.warn("No conference handler or conference not started yet");
762
-            callback();
763
-        }
764
-    }
765
-
766
-    /**
767
-     * Generate ssrc info object for a stream with the following properties:
768
-     * - ssrcs - Array of the ssrcs associated with the stream.
769
-     * - groups - Array of the groups associated with the stream.
770
-     */
771
-    generateNewStreamSSRCInfo () {
772
-        if(!this.session) {
773
-            logger.warn("The call haven't been started. " +
774
-                "Cannot generate ssrc info at the moment!");
775
-            return null;
776
-        }
777
-        return this.session.generateNewStreamSSRCInfo();
778
-    }
779
-
780
     setVideoMute (mute, callback) {
707
     setVideoMute (mute, callback) {
781
         this.sendVideoInfoPresence(mute);
708
         this.sendVideoInfoPresence(mute);
782
         if(callback)
709
         if(callback)
926
         return this.phonePin;
853
         return this.phonePin;
927
     }
854
     }
928
 
855
 
929
-    /**
930
-     * Returns the connection state for the current session.
931
-     */
932
-    getConnectionState () {
933
-        if(!this.session)
934
-            return null;
935
-        return this.session.getIceConnectionState();
936
-    }
937
-
938
     /**
856
     /**
939
      * Mutes remote participant.
857
      * Mutes remote participant.
940
      * @param jid of the participant
858
      * @param jid of the participant
982
      * rejected.
900
      * rejected.
983
      */
901
      */
984
     leave () {
902
     leave () {
985
-        this._dispose();
986
         return new Promise((resolve, reject) => {
903
         return new Promise((resolve, reject) => {
987
             let timeout = setTimeout(() => onMucLeft(true), 5000);
904
             let timeout = setTimeout(() => onMucLeft(true), 5000);
988
             let eventEmitter = this.eventEmitter;
905
             let eventEmitter = this.eventEmitter;
1001
             this.doLeave();
918
             this.doLeave();
1002
         });
919
         });
1003
     }
920
     }
1004
-
1005
-    /**
1006
-     * Disposes the conference, closes the jingle session.
1007
-     */
1008
-    _dispose () {
1009
-        if (this.session) {
1010
-            this.session.close();
1011
-        }
1012
-    }
1013
 }
921
 }

+ 1
- 11
modules/xmpp/JingleSession.js Zobrazit soubor

9
 import * as JingleSessionState from "./JingleSessionState";
9
 import * as JingleSessionState from "./JingleSessionState";
10
 
10
 
11
 function JingleSession(me, sid, peerjid, connection,
11
 function JingleSession(me, sid, peerjid, connection,
12
-                       media_constraints, ice_config, service, eventEmitter) {
12
+                       media_constraints, ice_config) {
13
     /**
13
     /**
14
      * Our JID.
14
      * Our JID.
15
      */
15
      */
30
      */
30
      */
31
     this.connection = connection;
31
     this.connection = connection;
32
 
32
 
33
-    /**
34
-     * The XMPP service.
35
-     */
36
-    this.service = service;
37
-
38
-    /**
39
-     * The event emitter.
40
-     */
41
-    this.eventEmitter = eventEmitter;
42
-
43
     /**
33
     /**
44
      * Whether to use dripping or not. Dripping is sending trickle candidates
34
      * Whether to use dripping or not. Dripping is sending trickle candidates
45
      * not one-by-one.
35
      * not one-by-one.

+ 49
- 19
modules/xmpp/JingleSessionPC.js Zobrazit soubor

23
  */
23
  */
24
 var IQ_TIMEOUT = 10000;
24
 var IQ_TIMEOUT = 10000;
25
 
25
 
26
-// Jingle stuff
26
+/**
27
+ * Creates new <tt>JingleSessionPC</tt>
28
+ * @param {string} me our JID
29
+ * @param {string} sid the Jingle Session ID - random string which
30
+ * identifies the session
31
+ * @param {string} peerjid remote peer JID
32
+ * @param {Strophe.Connection} connection Strophe XMPP connection instance
33
+ * used to send packets.
34
+ * @param media_constraints the media constraints object passed to
35
+ * createOffer/Answer, as defined by the WebRTC standard
36
+ * @param ice_config the ICE servers config object as defined by the WebRTC
37
+ * standard.
38
+ * @param {object} options a set of config options
39
+ * @param {boolean} options.webrtcIceUdpDisable <tt>true</tt> to block UDP
40
+ * candidates.
41
+ * @param {boolean} options.webrtcIceTcpDisable <tt>true</tt> to block TCP
42
+ * candidates.
43
+ * @param {boolean} options.failICE it's an option used in the tests. Set to
44
+ * <tt>true</tt> to block any real candidates and make the ICE fail.
45
+ */
27
 function JingleSessionPC(me, sid, peerjid, connection,
46
 function JingleSessionPC(me, sid, peerjid, connection,
28
-                         media_constraints, ice_config, service, eventEmitter) {
47
+                         media_constraints, ice_config, options) {
29
     JingleSession.call(this, me, sid, peerjid, connection,
48
     JingleSession.call(this, me, sid, peerjid, connection,
30
-                       media_constraints, ice_config, service, eventEmitter);
49
+                       media_constraints, ice_config);
31
 
50
 
32
     this.lasticecandidate = false;
51
     this.lasticecandidate = false;
33
     this.closed = false;
52
     this.closed = false;
60
      */
79
      */
61
     this.ssrcOwners = {};
80
     this.ssrcOwners = {};
62
 
81
 
63
-    this.webrtcIceUdpDisable = !!this.service.options.webrtcIceUdpDisable;
64
-    this.webrtcIceTcpDisable = !!this.service.options.webrtcIceTcpDisable;
82
+    this.webrtcIceUdpDisable = !!options.webrtcIceUdpDisable;
83
+    this.webrtcIceTcpDisable = !!options.webrtcIceTcpDisable;
65
     /**
84
     /**
66
      * Flag used to enforce ICE failure through the URL parameter for
85
      * Flag used to enforce ICE failure through the URL parameter for
67
      * the automatic testing purpose.
86
      * the automatic testing purpose.
68
      * @type {boolean}
87
      * @type {boolean}
69
      */
88
      */
70
-    this.failICE = !!this.service.options.failICE;
89
+    this.failICE = !!options.failICE;
71
 
90
 
72
     this.modificationQueue = async.queue(this._processQueueTasks.bind(this), 1);
91
     this.modificationQueue = async.queue(this._processQueueTasks.bind(this), 1);
73
 }
92
 }
85
     this.wasstable = false;
104
     this.wasstable = false;
86
 
105
 
87
     this.peerconnection = new TraceablePeerConnection(
106
     this.peerconnection = new TraceablePeerConnection(
88
-            this.connection.jingle.ice_config,
89
-            RTC.getPCConstraints(),
90
-            this);
107
+        this.connection.jingle.ice_config,
108
+        RTC.getPCConstraints(),
109
+        /* Options */
110
+        {
111
+            disableSimulcast: this.room.options.disableSimulcast,
112
+            disableRtx: this.room.options.disableRtx,
113
+            preferH264: this.room.options.preferH264
114
+        },
115
+        // TPC is using room's eventEmitter, so that all XMPPEvents can be
116
+        // captured from ChatRoom. But at the same time it makes hard
117
+        // or impossible to deal with more than one TPC instance without
118
+        // further refactoring.
119
+        this.room.eventEmitter);
91
 
120
 
92
     this.peerconnection.onicecandidate = function (ev) {
121
     this.peerconnection.onicecandidate = function (ev) {
93
         if (!ev) {
122
         if (!ev) {
240
             for (var i = 0; i < cands.length; i++) {
269
             for (var i = 0; i < cands.length; i++) {
241
                 var candidate = SDPUtil.candidateToJingle(cands[i].candidate);
270
                 var candidate = SDPUtil.candidateToJingle(cands[i].candidate);
242
                 // Mangle ICE candidate if 'failICE' test option is enabled
271
                 // Mangle ICE candidate if 'failICE' test option is enabled
243
-                if (this.service.options.failICE) {
272
+                if (this.failICE) {
244
                     candidate.ip = "1.1.1.1";
273
                     candidate.ip = "1.1.1.1";
245
                 }
274
                 }
246
                 cand.c('candidate', candidate).up();
275
                 cand.c('candidate', candidate).up();
846
  *  cycle after both operations are done.  Either oldStream or newStream
875
  *  cycle after both operations are done.  Either oldStream or newStream
847
  *  can be null; replacing a valid 'oldStream' with a null 'newStream'
876
  *  can be null; replacing a valid 'oldStream' with a null 'newStream'
848
  *  effectively just removes 'oldStream'
877
  *  effectively just removes 'oldStream'
849
- * @param oldStream the current stream in use to be replaced
850
- * @param newStream the new stream to use
878
+ * @param {JitsiLocalTrack|null} oldTrack the current track in use to be
879
+ * replaced
880
+ * @param {JitsiLocalTrack|null} newTrack the new track to use
851
  * @returns {Promise} which resolves once the replacement is complete
881
  * @returns {Promise} which resolves once the replacement is complete
852
  *  with no arguments or rejects with an error {string}
882
  *  with no arguments or rejects with an error {string}
853
  */
883
  */
854
-JingleSessionPC.prototype.replaceStream = function (oldStream, newStream) {
884
+JingleSessionPC.prototype.replaceTrack = function (oldTrack, newTrack) {
855
     return new Promise((resolve, reject) => {
885
     return new Promise((resolve, reject) => {
856
         let workFunction = (finishedCallback) => {
886
         let workFunction = (finishedCallback) => {
857
             let oldSdp = new SDP(this.peerconnection.localDescription.sdp);
887
             let oldSdp = new SDP(this.peerconnection.localDescription.sdp);
858
-            this.removeStreamFromPeerConnection(oldStream);
859
-            this.addStreamToPeerConnection(newStream);
888
+            this.removeStreamFromPeerConnection(oldTrack);
889
+            this.addStreamToPeerConnection(newTrack);
860
             this._renegotiate()
890
             this._renegotiate()
861
                 .then(() => {
891
                 .then(() => {
862
                     var newSdp = new SDP(this.peerconnection.localDescription.sdp);
892
                     var newSdp = new SDP(this.peerconnection.localDescription.sdp);
863
                     this.notifyMySSRCUpdate(oldSdp, newSdp);
893
                     this.notifyMySSRCUpdate(oldSdp, newSdp);
864
                     finishedCallback();
894
                     finishedCallback();
865
                 }, (error) => {
895
                 }, (error) => {
866
-                    logger.error("replaceStream renegotiation failed: " + error);
896
+                    logger.error("replaceTrack renegotiation failed: " + error);
867
                     finishedCallback(error);
897
                     finishedCallback(error);
868
                 });
898
                 });
869
         };
899
         };
952
  * stream.
982
  * stream.
953
  * @param dontModifySources {boolean} if true _modifySources won't be called.
983
  * @param dontModifySources {boolean} if true _modifySources won't be called.
954
  * Used for streams added before the call start.
984
  * Used for streams added before the call start.
955
- * NOTE(brian): there is a decent amount of overlap here with replaceStream that
985
+ * NOTE(brian): there is a decent amount of overlap here with replaceTrack that
956
  *  could be re-used...however we can't leverage that currently because the
986
  *  could be re-used...however we can't leverage that currently because the
957
  *  extra work we do here must be in the work function context and if we
987
  *  extra work we do here must be in the work function context and if we
958
- *  then called replaceStream we'd be adding another task on the queue
959
- *  from within a task which would then deadlock.  The 'replaceStream' core
988
+ *  then called replaceTrack we'd be adding another task on the queue
989
+ *  from within a task which would then deadlock.  The 'replaceTrack' core
960
  *  logic should be moved into a helper function that could be called within
990
  *  logic should be moved into a helper function that could be called within
961
  *  the 'doReplaceStream' task or the 'doAddStream' task (for example)
991
  *  the 'doReplaceStream' task or the 'doAddStream' task (for example)
962
  */
992
  */

+ 28
- 11
modules/xmpp/TraceablePeerConnection.js Zobrazit soubor

12
 
12
 
13
 var SIMULCAST_LAYERS = 3;
13
 var SIMULCAST_LAYERS = 3;
14
 
14
 
15
-function TraceablePeerConnection(ice_config, constraints, session) {
15
+/**
16
+ * Creates new instance of 'TraceablePeerConnection'.
17
+ *
18
+ * @param {object} ice_config WebRTC 'PeerConnection' ICE config
19
+ * @param {object} constraints WebRTC 'PeerConnection' constraints
20
+ * @param {object} options <tt>TracablePeerConnection</tt> config options.
21
+ * @param {boolean} options.disableSimulcast if set to 'true' will disable
22
+ * the simulcast
23
+ * @param {boolean} options.disableRtx if set to 'true' will disable the RTX
24
+ * @param {boolean} options.preferH264 if set to 'true' H264 will be preferred
25
+ * over other video codecs.
26
+ * @param {EventEmitter} eventEmitter the emitter which wil be used by the new
27
+ * instance to emit events.
28
+ *
29
+ * @constructor
30
+ */
31
+function TraceablePeerConnection(ice_config,
32
+                                 constraints, options, eventEmitter) {
16
     var self = this;
33
     var self = this;
17
-    this.session = session;
34
+    this.options = options;
18
     var RTCPeerConnectionType = null;
35
     var RTCPeerConnectionType = null;
19
     if (RTCBrowserType.isFirefox()) {
36
     if (RTCBrowserType.isFirefox()) {
20
         RTCPeerConnectionType = mozRTCPeerConnection;
37
         RTCPeerConnectionType = mozRTCPeerConnection;
35
         explodeRemoteSimulcast: false});
52
         explodeRemoteSimulcast: false});
36
     this.sdpConsistency = new SdpConsistency();
53
     this.sdpConsistency = new SdpConsistency();
37
     this.rtxModifier = new RtxModifier();
54
     this.rtxModifier = new RtxModifier();
38
-    this.eventEmitter = this.session.room.eventEmitter;
55
+    this.eventEmitter = eventEmitter;
39
 
56
 
40
     // override as desired
57
     // override as desired
41
     this.trace = function (what, info) {
58
     this.trace = function (what, info) {
318
         this.peerconnection.addStream(stream);
335
         this.peerconnection.addStream(stream);
319
     if (ssrcInfo && ssrcInfo.type === "addMuted") {
336
     if (ssrcInfo && ssrcInfo.type === "addMuted") {
320
         this.sdpConsistency.setPrimarySsrc(ssrcInfo.ssrc.ssrcs[0]);
337
         this.sdpConsistency.setPrimarySsrc(ssrcInfo.ssrc.ssrcs[0]);
321
-        const simGroup = 
338
+        const simGroup =
322
             ssrcInfo.ssrc.groups.find(groupInfo => {
339
             ssrcInfo.ssrc.groups.find(groupInfo => {
323
                 return groupInfo.group.semantics === "SIM";
340
                 return groupInfo.group.semantics === "SIM";
324
             });
341
             });
333
         if (fidGroups) {
350
         if (fidGroups) {
334
             const rtxSsrcMapping = new Map();
351
             const rtxSsrcMapping = new Map();
335
             fidGroups.forEach(fidGroup => {
352
             fidGroups.forEach(fidGroup => {
336
-                const fidGroupSsrcs = 
353
+                const fidGroupSsrcs =
337
                     SDPUtil.parseGroupSsrcs(fidGroup.group);
354
                     SDPUtil.parseGroupSsrcs(fidGroup.group);
338
                 const primarySsrc = fidGroupSsrcs[0];
355
                 const primarySsrc = fidGroupSsrcs[0];
339
                 const rtxSsrc = fidGroupSsrcs[1];
356
                 const rtxSsrc = fidGroupSsrcs[1];
389
     description = this.simulcast.mungeRemoteDescription(description);
406
     description = this.simulcast.mungeRemoteDescription(description);
390
     this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(description));
407
     this.trace('setRemoteDescription::postTransform (simulcast)', dumpSDP(description));
391
 
408
 
392
-    if (this.session.room.options.preferH264) {
409
+    if (this.options.preferH264) {
393
         const parsedSdp = transform.parse(description.sdp);
410
         const parsedSdp = transform.parse(description.sdp);
394
         const videoMLine = parsedSdp.media.find(m => m.type === "video");
411
         const videoMLine = parsedSdp.media.find(m => m.type === "video");
395
         SDPUtil.preferVideoCodec(videoMLine, "h264");
412
         SDPUtil.preferVideoCodec(videoMLine, "h264");
539
                 }
556
                 }
540
 
557
 
541
                 // Add simulcast streams if simulcast is enabled
558
                 // Add simulcast streams if simulcast is enabled
542
-                if (!this.session.room.options.disableSimulcast
559
+                if (!this.options.disableSimulcast
543
                     && this.simulcast.isSupported()) {
560
                     && this.simulcast.isSupported()) {
544
                     answer = this.simulcast.mungeLocalDescription(answer);
561
                     answer = this.simulcast.mungeLocalDescription(answer);
545
                     this.trace(
562
                     this.trace(
547
                         dumpSDP(answer));
564
                         dumpSDP(answer));
548
                 }
565
                 }
549
 
566
 
550
-                if (!this.session.room.options.disableRtx && !RTCBrowserType.isFirefox()) {
567
+                if (!this.options.disableRtx && !RTCBrowserType.isFirefox()) {
551
                     answer.sdp = this.rtxModifier.modifyRtxSsrcs(answer.sdp);
568
                     answer.sdp = this.rtxModifier.modifyRtxSsrcs(answer.sdp);
552
                     this.trace(
569
                     this.trace(
553
                         'createAnswerOnSuccess::postTransform (rtx modifier)',
570
                         'createAnswerOnSuccess::postTransform (rtx modifier)',
623
  */
640
  */
624
 TraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function () {
641
 TraceablePeerConnection.prototype.generateNewStreamSSRCInfo = function () {
625
     let ssrcInfo = {ssrcs: [], groups: []};
642
     let ssrcInfo = {ssrcs: [], groups: []};
626
-    if (!this.session.room.options.disableSimulcast
643
+    if (!this.options.disableSimulcast
627
         && this.simulcast.isSupported()) {
644
         && this.simulcast.isSupported()) {
628
         for (let i = 0; i < SIMULCAST_LAYERS; i++) {
645
         for (let i = 0; i < SIMULCAST_LAYERS; i++) {
629
             ssrcInfo.ssrcs.push(SDPUtil.generateSsrc());
646
             ssrcInfo.ssrcs.push(SDPUtil.generateSsrc());
635
     } else {
652
     } else {
636
         ssrcInfo = {ssrcs: [SDPUtil.generateSsrc()], groups: []};
653
         ssrcInfo = {ssrcs: [SDPUtil.generateSsrc()], groups: []};
637
     }
654
     }
638
-    if (!this.session.room.options.disableRtx) {
655
+    if (!this.options.disableRtx) {
639
         // Specifically use a for loop here because we'll
656
         // Specifically use a for loop here because we'll
640
         //  be adding to the list we're iterating over, so we
657
         //  be adding to the list we're iterating over, so we
641
         //  only want to iterate through the items originally
658
         //  only want to iterate through the items originally
647
             ssrcInfo.ssrcs.push(rtxSsrc);
664
             ssrcInfo.ssrcs.push(rtxSsrc);
648
             ssrcInfo.groups.push({
665
             ssrcInfo.groups.push({
649
                 primarySSRC: primarySsrc,
666
                 primarySSRC: primarySsrc,
650
-                group: { 
667
+                group: {
651
                     ssrcs: primarySsrc + " " + rtxSsrc,
668
                     ssrcs: primarySsrc + " " + rtxSsrc,
652
                     semantics: "FID"
669
                     semantics: "FID"
653
                 }
670
                 }

+ 0
- 8
modules/xmpp/strophe.emuc.js Zobrazit soubor

106
         return true;
106
         return true;
107
     }
107
     }
108
 
108
 
109
-    setJingleSession (from, session) {
110
-        const room = this.rooms[Strophe.getBareJidFromJid(from)];
111
-        if(!room)
112
-            return;
113
-
114
-        room.setJingleSession(session);
115
-    }
116
-
117
     onMute(iq) {
109
     onMute(iq) {
118
         const from = iq.getAttribute('from');
110
         const from = iq.getAttribute('from');
119
         const room = this.rooms[Strophe.getBareJidFromJid(from)];
111
         const room = this.rooms[Strophe.getBareJidFromJid(from)];

+ 1
- 1
modules/xmpp/strophe.jingle.js Zobrazit soubor

90
                         fromJid,
90
                         fromJid,
91
                         this.connection,
91
                         this.connection,
92
                         this.media_constraints,
92
                         this.media_constraints,
93
-                        this.ice_config, this.xmpp);
93
+                        this.ice_config, this.xmpp.options);
94
 
94
 
95
                 this.sessions[sess.sid] = sess;
95
                 this.sessions[sess.sid] = sess;
96
 
96
 

Načítá se…
Zrušit
Uložit