浏览代码

Fixes TRACK_REMOVED event.

master
hristoterezov 10 年前
父节点
当前提交
ae85fc66e5
共有 7 个文件被更改,包括 316 次插入147 次删除
  1. 17
    9
      JitsiConference.js
  2. 7
    6
      JitsiParticipant.js
  3. 3
    0
      doc/example/example.js
  4. 262
    111
      lib-jitsi-meet.js
  5. 0
    21
      modules/RTC/JitsiLocalTrack.js
  6. 6
    0
      modules/RTC/JitsiRemoteTrack.js
  7. 21
    0
      modules/RTC/JitsiTrack.js

+ 17
- 9
JitsiConference.js 查看文件

4
 var RTCEvents = require("./service/RTC/RTCEvents");
4
 var RTCEvents = require("./service/RTC/RTCEvents");
5
 var EventEmitter = require("events");
5
 var EventEmitter = require("events");
6
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
6
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
7
+var JitsiParticipant = require("./JitsiParticipant");
7
 
8
 
8
 /**
9
 /**
9
  * Creates a JitsiConference object with the given name and properties.
10
  * Creates a JitsiConference object with the given name and properties.
23
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
24
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
24
     this.rtc = new RTC(this.room, options);
25
     this.rtc = new RTC(this.room, options);
25
     setupListeners(this);
26
     setupListeners(this);
27
+    this.participants = {};
26
 }
28
 }
27
 
29
 
28
 /**
30
 /**
171
  * @return Object a list of participant identifiers containing all conference participants.
173
  * @return Object a list of participant identifiers containing all conference participants.
172
  */
174
  */
173
 JitsiConference.prototype.getParticipants = function() {
175
 JitsiConference.prototype.getParticipants = function() {
174
-
176
+    return this.participants;
175
 }
177
 }
176
 
178
 
177
 /**
179
 /**
180
  * @param id the id of the participant.
182
  * @param id the id of the participant.
181
  */
183
  */
182
 JitsiConference.prototype.getParticipantById = function(id) {
184
 JitsiConference.prototype.getParticipantById = function(id) {
185
+    return this.participants[id];
186
+}
183
 
187
 
188
+JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
189
+    this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, Strophe.getResourceFromJid(jid));
190
+//    this.participants[jid] = new JitsiParticipant();
184
 }
191
 }
185
 
192
 
186
 /**
193
 /**
195
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
202
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
196
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
203
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
197
     });
204
     });
198
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
205
+    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, function (stream) {
206
+        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
207
+    });
208
+    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, function (stream) {
199
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
209
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
200
     })
210
     })
201
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
211
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
202
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
212
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
203
     });
213
     });
204
-    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
205
-        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
206
-    });
214
+//    FIXME
215
+//    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
216
+//        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
217
+//    });
207
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
218
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
208
         conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
219
         conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
209
     });
220
     });
218
                 lastNEndpoints, endpointsEnteringLastN);
229
                 lastNEndpoints, endpointsEnteringLastN);
219
         });
230
         });
220
 
231
 
221
-    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED,
222
-        function (jid, email, nick) {
223
-            conference.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, Strophe.getResourceFromJid(jid));
224
-        });
232
+    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED, conference.onMemberJoined.bind(conference));
225
     conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT,function (jid) {
233
     conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT,function (jid) {
226
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, Strophe.getResourceFromJid(jid));
234
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, Strophe.getResourceFromJid(jid));
227
     });
235
     });

+ 7
- 6
JitsiParticipant.js 查看文件

1
 /**
1
 /**
2
  * Represents a participant in (a member of) a conference.
2
  * Represents a participant in (a member of) a conference.
3
  */
3
  */
4
-function JitsiParticipant(){
5
-
4
+function JitsiParticipant(id, conference, displayName){
5
+    this._id = id;
6
+    this._conference = conference;
7
+    this._displayName = displayName;
6
 }
8
 }
7
 
9
 
8
 /**
10
 /**
9
  * @returns {JitsiConference} The conference that this participant belongs to.
11
  * @returns {JitsiConference} The conference that this participant belongs to.
10
  */
12
  */
11
 JitsiParticipant.prototype.getConference = function() {
13
 JitsiParticipant.prototype.getConference = function() {
12
-
14
+    return this._conference;
13
 }
15
 }
14
 
16
 
15
 /**
17
 /**
23
  * @returns {String} The ID (i.e. JID) of this participant.
25
  * @returns {String} The ID (i.e. JID) of this participant.
24
  */
26
  */
25
 JitsiParticipant.prototype.getId = function() {
27
 JitsiParticipant.prototype.getId = function() {
26
-
28
+    return this._id;
27
 }
29
 }
28
 
30
 
29
 /**
31
 /**
30
  * @returns {String} The human-readable display name of this participant.
32
  * @returns {String} The human-readable display name of this participant.
31
  */
33
  */
32
 JitsiParticipant.prototype.getDisplayName = function() {
34
 JitsiParticipant.prototype.getDisplayName = function() {
33
-
35
+    return this._displayName;
34
 }
36
 }
35
 
37
 
36
 /**
38
 /**
37
  * @returns {Boolean} Whether this participant is a moderator or not.
39
  * @returns {Boolean} Whether this participant is a moderator or not.
38
  */
40
  */
39
 JitsiParticipant.prototype.isModerator = function() {
41
 JitsiParticipant.prototype.isModerator = function() {
40
-
41
 }
42
 }
42
 
43
 
43
 // Gets a link to an etherpad instance advertised by the participant?
44
 // Gets a link to an etherpad instance advertised by the participant?

+ 3
- 0
doc/example/example.js 查看文件

67
     room = connection.initJitsiConference("conference1", confOptions);
67
     room = connection.initJitsiConference("conference1", confOptions);
68
     room.createLocalTracks().then(onLocalTracks);
68
     room.createLocalTracks().then(onLocalTracks);
69
     room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
69
     room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
70
+    room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function () {
71
+        console.debug("track removed!!!");
72
+    });
70
     room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
73
     room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
71
     room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ remoteTracks[id] = [];});
74
     room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ remoteTracks[id] = [];});
72
     room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);
75
     room.on(JitsiMeetJS.events.conference.USER_LEFT, onUserLeft);

+ 262
- 111
lib-jitsi-meet.js 查看文件

5
 var RTCEvents = require("./service/RTC/RTCEvents");
5
 var RTCEvents = require("./service/RTC/RTCEvents");
6
 var EventEmitter = require("events");
6
 var EventEmitter = require("events");
7
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
7
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
8
+var JitsiParticipant = require("./JitsiParticipant");
8
 
9
 
9
 /**
10
 /**
10
  * Creates a JitsiConference object with the given name and properties.
11
  * Creates a JitsiConference object with the given name and properties.
24
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
25
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
25
     this.rtc = new RTC(this.room, options);
26
     this.rtc = new RTC(this.room, options);
26
     setupListeners(this);
27
     setupListeners(this);
28
+    this.participants = {};
27
 }
29
 }
28
 
30
 
29
 /**
31
 /**
172
  * @return Object a list of participant identifiers containing all conference participants.
174
  * @return Object a list of participant identifiers containing all conference participants.
173
  */
175
  */
174
 JitsiConference.prototype.getParticipants = function() {
176
 JitsiConference.prototype.getParticipants = function() {
175
-
177
+    return this.participants;
176
 }
178
 }
177
 
179
 
178
 /**
180
 /**
181
  * @param id the id of the participant.
183
  * @param id the id of the participant.
182
  */
184
  */
183
 JitsiConference.prototype.getParticipantById = function(id) {
185
 JitsiConference.prototype.getParticipantById = function(id) {
186
+    return this.participants[id];
187
+}
184
 
188
 
189
+JitsiConference.prototype.onMemberJoined = function (jid, email, nick) {
190
+    this.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, Strophe.getResourceFromJid(jid));
191
+//    this.participants[jid] = new JitsiParticipant();
185
 }
192
 }
186
 
193
 
187
 /**
194
 /**
196
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
203
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
197
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
204
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
198
     });
205
     });
199
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
206
+    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, function (stream) {
207
+        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
208
+    });
209
+    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, function (stream) {
200
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
210
         conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
201
     })
211
     })
202
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
212
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
203
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
213
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
204
     });
214
     });
205
-    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
206
-        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
207
-    });
215
+//    FIXME
216
+//    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
217
+//        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
218
+//    });
208
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
219
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
209
         conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
220
         conference.eventEmitter.emit(JitsiConferenceEvents.ACTIVE_SPEAKER_CHANGED, id);
210
     });
221
     });
219
                 lastNEndpoints, endpointsEnteringLastN);
230
                 lastNEndpoints, endpointsEnteringLastN);
220
         });
231
         });
221
 
232
 
222
-    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED,
223
-        function (jid, email, nick) {
224
-            conference.eventEmitter.emit(JitsiConferenceEvents.USER_JOINED, Strophe.getResourceFromJid(jid));
225
-        });
233
+    conference.room.addListener(XMPPEvents.MUC_MEMBER_JOINED, conference.onMemberJoined.bind(conference));
226
     conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT,function (jid) {
234
     conference.room.addListener(XMPPEvents.MUC_MEMBER_LEFT,function (jid) {
227
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, Strophe.getResourceFromJid(jid));
235
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_LEFT, Strophe.getResourceFromJid(jid));
228
     });
236
     });
231
 
239
 
232
 module.exports = JitsiConference;
240
 module.exports = JitsiConference;
233
 
241
 
234
-},{"./JitsiConferenceEvents":3,"./modules/RTC/RTC":12,"./service/RTC/RTCEvents":70,"./service/RTC/StreamEventTypes":72,"./service/xmpp/XMPPEvents":75,"events":76}],2:[function(require,module,exports){
242
+},{"./JitsiConferenceEvents":3,"./JitsiParticipant":8,"./modules/RTC/RTC":13,"./service/RTC/RTCEvents":71,"./service/RTC/StreamEventTypes":73,"./service/xmpp/XMPPEvents":76,"events":77}],2:[function(require,module,exports){
235
 /**
243
 /**
236
  * Enumeration with the errors for the conference.
244
  * Enumeration with the errors for the conference.
237
  * @type {{string: string}}
245
  * @type {{string: string}}
415
 
423
 
416
 module.exports = JitsiConnection;
424
 module.exports = JitsiConnection;
417
 
425
 
418
-},{"./JitsiConference":1,"./modules/xmpp/xmpp":32}],5:[function(require,module,exports){
426
+},{"./JitsiConference":1,"./modules/xmpp/xmpp":33}],5:[function(require,module,exports){
419
 /**
427
 /**
420
  * Enumeration with the errors for the connection.
428
  * Enumeration with the errors for the connection.
421
  * @type {{string: string}}
429
  * @type {{string: string}}
496
 
504
 
497
 module.exports = LibJitsiMeet;
505
 module.exports = LibJitsiMeet;
498
 
506
 
499
-},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./modules/RTC/RTC":12,"es6-promise":34}],8:[function(require,module,exports){
507
+},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./modules/RTC/RTC":13,"es6-promise":35}],8:[function(require,module,exports){
508
+/**
509
+ * Represents a participant in (a member of) a conference.
510
+ */
511
+function JitsiParticipant(id, conference, displayName){
512
+    this._id = id;
513
+    this._conference = conference;
514
+    this._displayName = displayName;
515
+}
516
+
517
+/**
518
+ * @returns {JitsiConference} The conference that this participant belongs to.
519
+ */
520
+JitsiParticipant.prototype.getConference = function() {
521
+    return this._conference;
522
+}
523
+
524
+/**
525
+ * @returns {Array.<JitsiTrack>} The list of media tracks for this participant.
526
+ */
527
+JitsiParticipant.prototype.getTracks = function() {
528
+
529
+}
530
+
531
+/**
532
+ * @returns {String} The ID (i.e. JID) of this participant.
533
+ */
534
+JitsiParticipant.prototype.getId = function() {
535
+    return this._id;
536
+}
537
+
538
+/**
539
+ * @returns {String} The human-readable display name of this participant.
540
+ */
541
+JitsiParticipant.prototype.getDisplayName = function() {
542
+    return this._displayName;
543
+}
544
+
545
+/**
546
+ * @returns {Boolean} Whether this participant is a moderator or not.
547
+ */
548
+JitsiParticipant.prototype.isModerator = function() {
549
+}
550
+
551
+// Gets a link to an etherpad instance advertised by the participant?
552
+//JitsiParticipant.prototype.getEtherpad = function() {
553
+//
554
+//}
555
+
556
+
557
+/*
558
+ * @returns {Boolean} Whether this participant has muted their audio.
559
+ */
560
+JitsiParticipant.prototype.isAudioMuted = function() {
561
+
562
+}
563
+
564
+/*
565
+ * @returns {Boolean} Whether this participant has muted their video.
566
+ */
567
+JitsiParticipant.prototype.isVideoMuted = function() {
568
+
569
+}
570
+
571
+/*
572
+ * @returns {???} The latest statistics reported by this participant (i.e. info used to populate the GSM bars)
573
+ * TODO: do we expose this or handle it internally?
574
+ */
575
+JitsiParticipant.prototype.getLatestStats = function() {
576
+
577
+}
578
+
579
+/**
580
+ * @returns {String} The role of this participant.
581
+ */
582
+JitsiParticipant.prototype.getRole = function() {
583
+
584
+}
585
+
586
+/*
587
+ * @returns {Boolean} Whether this participant is the conference focus (i.e. jicofo).
588
+ */
589
+JitsiParticipant.prototype.isFocus = function() {
590
+
591
+}
592
+
593
+/*
594
+ * @returns {Boolean} Whether this participant is a conference recorder (i.e. jirecon).
595
+ */
596
+JitsiParticipant.prototype.isRecorder = function() {
597
+
598
+}
599
+
600
+/*
601
+ * @returns {Boolean} Whether this participant is a SIP gateway (i.e. jigasi).
602
+ */
603
+JitsiParticipant.prototype.isSipGateway = function() {
604
+
605
+}
606
+
607
+/**
608
+ * @returns {String} The ID for this participant's avatar.
609
+ */
610
+JitsiParticipant.prototype.getAvatarId = function() {
611
+
612
+}
613
+
614
+/**
615
+ * @returns {Boolean} Whether this participant is currently sharing their screen.
616
+ */
617
+JitsiParticipant.prototype.isScreenSharing = function() {
618
+
619
+}
620
+
621
+/**
622
+ * @returns {String} The user agent of this participant (i.e. browser userAgent string).
623
+ */
624
+JitsiParticipant.prototype.getUserAgent = function() {
625
+
626
+}
627
+
628
+/**
629
+ * Kicks the participant from the conference (requires certain privileges).
630
+ */
631
+JitsiParticipant.prototype.kick = function() {
632
+
633
+}
634
+
635
+/**
636
+ * Asks this participant to mute themselves.
637
+ */
638
+JitsiParticipant.prototype.askToMute = function() {
639
+
640
+}
641
+
642
+
643
+module.exports = JitsiParticipant();
644
+
645
+},{}],9:[function(require,module,exports){
500
 /* global config, APP, Strophe */
646
 /* global config, APP, Strophe */
501
 
647
 
502
 // cache datachannels to avoid garbage collection
648
 // cache datachannels to avoid garbage collection
683
 module.exports = DataChannels;
829
 module.exports = DataChannels;
684
 
830
 
685
 
831
 
686
-},{"../../service/RTC/RTCEvents":70}],9:[function(require,module,exports){
832
+},{"../../service/RTC/RTCEvents":71}],10:[function(require,module,exports){
687
 var JitsiTrack = require("./JitsiTrack");
833
 var JitsiTrack = require("./JitsiTrack");
688
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
834
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
689
 var RTCEvents = require("../../service/RTC/RTCEvents");
835
 var RTCEvents = require("../../service/RTC/RTCEvents");
690
-var RTCBrowserType = require("./RTCBrowserType");
691
-
692
-/**
693
- * This implements 'onended' callback normally fired by WebRTC after the stream
694
- * is stopped. There is no such behaviour yet in FF, so we have to add it.
695
- * @param stream original WebRTC stream object to which 'onended' handling
696
- *               will be added.
697
- */
698
-function implementOnEndedHandling(stream) {
699
-    var originalStop = stream.stop;
700
-    stream.stop = function () {
701
-        originalStop.apply(stream);
702
-        if (!stream.ended) {
703
-            stream.ended = true;
704
-            stream.onended();
705
-        }
706
-    };
707
-}
708
 
836
 
709
 /**
837
 /**
710
  * Represents a single media track (either audio or video).
838
  * Represents a single media track (either audio or video).
721
     this.stream.onended = function () {
849
     this.stream.onended = function () {
722
         this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
850
         this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
723
     }.bind(this);
851
     }.bind(this);
724
-    if (RTCBrowserType.isFirefox()) {
725
-        implementOnEndedHandling(this.stream);
726
-    }
727
 }
852
 }
728
 
853
 
729
 JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
854
 JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
804
 
929
 
805
 module.exports = JitsiLocalTrack;
930
 module.exports = JitsiLocalTrack;
806
 
931
 
807
-},{"../../service/RTC/RTCEvents":70,"../../service/RTC/StreamEventTypes":72,"./JitsiTrack":11,"./RTCBrowserType":13}],10:[function(require,module,exports){
932
+},{"../../service/RTC/RTCEvents":71,"../../service/RTC/StreamEventTypes":73,"./JitsiTrack":12}],11:[function(require,module,exports){
808
 var JitsiTrack = require("./JitsiTrack");
933
 var JitsiTrack = require("./JitsiTrack");
934
+var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
809
 
935
 
810
 /**
936
 /**
811
  * Represents a single media track (either audio or video).
937
  * Represents a single media track (either audio or video).
821
     this.ssrc = ssrc;
947
     this.ssrc = ssrc;
822
     this.muted = false;
948
     this.muted = false;
823
     this.eventEmitter = eventEmitter;
949
     this.eventEmitter = eventEmitter;
950
+    var self = this;
951
+    if(this.stream)
952
+        this.stream.onended = function () {
953
+            eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, self);
954
+        }
824
 }
955
 }
825
 
956
 
826
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
957
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
844
 
975
 
845
 module.exports = JitsiRemoteTrack;
976
 module.exports = JitsiRemoteTrack;
846
 
977
 
847
-},{"./JitsiTrack":11}],11:[function(require,module,exports){
978
+},{"../../service/RTC/StreamEventTypes":73,"./JitsiTrack":12}],12:[function(require,module,exports){
848
 var RTC = require("./RTCUtils");
979
 var RTC = require("./RTCUtils");
980
+var RTCBrowserType = require("./RTCBrowserType");
981
+
982
+/**
983
+ * This implements 'onended' callback normally fired by WebRTC after the stream
984
+ * is stopped. There is no such behaviour yet in FF, so we have to add it.
985
+ * @param stream original WebRTC stream object to which 'onended' handling
986
+ *               will be added.
987
+ */
988
+function implementOnEndedHandling(stream) {
989
+    var originalStop = stream.stop;
990
+    stream.stop = function () {
991
+        originalStop.apply(stream);
992
+        if (!stream.ended) {
993
+            stream.ended = true;
994
+            stream.onended();
995
+        }
996
+    };
997
+}
849
 
998
 
850
 /**
999
 /**
851
  * Represents a single media track (either audio or video).
1000
  * Represents a single media track (either audio or video).
866
             return this.stream.getVideoTracks();
1015
             return this.stream.getVideoTracks();
867
         }.bind(this);
1016
         }.bind(this);
868
     }
1017
     }
1018
+    if (RTCBrowserType.isFirefox() && this.stream) {
1019
+        implementOnEndedHandling(this.stream);
1020
+    }
869
 }
1021
 }
870
 
1022
 
871
 /**
1023
 /**
963
 
1115
 
964
 module.exports = JitsiTrack;
1116
 module.exports = JitsiTrack;
965
 
1117
 
966
-},{"./RTCUtils":14}],12:[function(require,module,exports){
1118
+},{"./RTCBrowserType":14,"./RTCUtils":15}],13:[function(require,module,exports){
967
 /* global APP */
1119
 /* global APP */
968
 var EventEmitter = require("events");
1120
 var EventEmitter = require("events");
969
 var RTCBrowserType = require("./RTCBrowserType");
1121
 var RTCBrowserType = require("./RTCBrowserType");
1291
 
1443
 
1292
 module.exports = RTC;
1444
 module.exports = RTC;
1293
 
1445
 
1294
-},{"../../service/RTC/MediaStreamTypes":69,"../../service/RTC/RTCEvents.js":70,"../../service/RTC/StreamEventTypes.js":72,"../../service/desktopsharing/DesktopSharingEventTypes":74,"../../service/xmpp/XMPPEvents":75,"../desktopsharing/desktopsharing":16,"./DataChannels":8,"./JitsiLocalTrack.js":9,"./JitsiRemoteTrack.js":10,"./RTCBrowserType":13,"./RTCUtils.js":14,"events":76}],13:[function(require,module,exports){
1446
+},{"../../service/RTC/MediaStreamTypes":70,"../../service/RTC/RTCEvents.js":71,"../../service/RTC/StreamEventTypes.js":73,"../../service/desktopsharing/DesktopSharingEventTypes":75,"../../service/xmpp/XMPPEvents":76,"../desktopsharing/desktopsharing":17,"./DataChannels":9,"./JitsiLocalTrack.js":10,"./JitsiRemoteTrack.js":11,"./RTCBrowserType":14,"./RTCUtils.js":15,"events":77}],14:[function(require,module,exports){
1295
 
1447
 
1296
 var currentBrowser;
1448
 var currentBrowser;
1297
 
1449
 
1453
 browserVersion = detectBrowser();
1605
 browserVersion = detectBrowser();
1454
 
1606
 
1455
 module.exports = RTCBrowserType;
1607
 module.exports = RTCBrowserType;
1456
-},{}],14:[function(require,module,exports){
1608
+},{}],15:[function(require,module,exports){
1457
 /* global config, require, attachMediaStream, getUserMedia */
1609
 /* global config, require, attachMediaStream, getUserMedia */
1458
 var RTCBrowserType = require("./RTCBrowserType");
1610
 var RTCBrowserType = require("./RTCBrowserType");
1459
 var Resolutions = require("../../service/RTC/Resolutions");
1611
 var Resolutions = require("../../service/RTC/Resolutions");
2010
 
2162
 
2011
 module.exports = RTCUtils;
2163
 module.exports = RTCUtils;
2012
 
2164
 
2013
-},{"../../service/RTC/Resolutions":71,"../xmpp/SDPUtil":24,"./RTCBrowserType":13,"./adapter.screenshare":15,"events":76}],15:[function(require,module,exports){
2165
+},{"../../service/RTC/Resolutions":72,"../xmpp/SDPUtil":25,"./RTCBrowserType":14,"./adapter.screenshare":16,"events":77}],16:[function(require,module,exports){
2014
 /*! adapterjs - custom version from - 2015-08-12 */
2166
 /*! adapterjs - custom version from - 2015-08-12 */
2015
 
2167
 
2016
 // Adapter's interface.
2168
 // Adapter's interface.
3341
     };
3493
     };
3342
   }
3494
   }
3343
 })();
3495
 })();
3344
-},{}],16:[function(require,module,exports){
3496
+},{}],17:[function(require,module,exports){
3345
 /* global $, alert, APP, changeLocalVideo, chrome, config, getConferenceHandler,
3497
 /* global $, alert, APP, changeLocalVideo, chrome, config, getConferenceHandler,
3346
  getUserMediaWithConstraints */
3498
  getUserMediaWithConstraints */
3347
 /**
3499
 /**
3730
 };
3882
 };
3731
 
3883
 
3732
 
3884
 
3733
-},{"../../service/RTC/RTCEvents":70,"../../service/desktopsharing/DesktopSharingEventTypes":74,"../RTC/RTCBrowserType":13,"../RTC/adapter.screenshare":15,"events":76}],17:[function(require,module,exports){
3885
+},{"../../service/RTC/RTCEvents":71,"../../service/desktopsharing/DesktopSharingEventTypes":75,"../RTC/RTCBrowserType":14,"../RTC/adapter.screenshare":16,"events":77}],18:[function(require,module,exports){
3734
 function supportsLocalStorage() {
3886
 function supportsLocalStorage() {
3735
     try {
3887
     try {
3736
         return 'localStorage' in window && window.localStorage !== null;
3888
         return 'localStorage' in window && window.localStorage !== null;
3812
 
3964
 
3813
 module.exports = Settings;
3965
 module.exports = Settings;
3814
 
3966
 
3815
-},{}],18:[function(require,module,exports){
3967
+},{}],19:[function(require,module,exports){
3816
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
3968
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
3817
 var Moderator = require("./moderator");
3969
 var Moderator = require("./moderator");
3818
 var EventEmitter = require("events");
3970
 var EventEmitter = require("events");
4392
 }
4544
 }
4393
 
4545
 
4394
 module.exports = ChatRoom;
4546
 module.exports = ChatRoom;
4395
-},{"../../service/xmpp/XMPPEvents":75,"./moderator":26,"events":76}],19:[function(require,module,exports){
4547
+},{"../../service/xmpp/XMPPEvents":76,"./moderator":27,"events":77}],20:[function(require,module,exports){
4396
 /*
4548
 /*
4397
  * JingleSession provides an API to manage a single Jingle session. We will
4549
  * JingleSession provides an API to manage a single Jingle session. We will
4398
  * have different implementations depending on the underlying interface used
4550
  * have different implementations depending on the underlying interface used
4524
 
4676
 
4525
 module.exports = JingleSession;
4677
 module.exports = JingleSession;
4526
 
4678
 
4527
-},{}],20:[function(require,module,exports){
4679
+},{}],21:[function(require,module,exports){
4528
 /* jshint -W117 */
4680
 /* jshint -W117 */
4529
 var JingleSession = require("./JingleSession");
4681
 var JingleSession = require("./JingleSession");
4530
 var TraceablePeerConnection = require("./TraceablePeerConnection");
4682
 var TraceablePeerConnection = require("./TraceablePeerConnection");
4632
         }
4784
         }
4633
     };
4785
     };
4634
     this.peerconnection.onremovestream = function (event) {
4786
     this.peerconnection.onremovestream = function (event) {
4635
-        // Remove the stream from remoteStreams
4636
-        // FIXME: remotestreamremoved.jingle not defined anywhere(unused)
4637
 
4787
 
4638
-        $(document).trigger('remotestreamremoved.jingle', [event, self.sid]);
4639
     };
4788
     };
4640
     this.peerconnection.onsignalingstatechange = function (event) {
4789
     this.peerconnection.onsignalingstatechange = function (event) {
4641
         if (!(self && self.peerconnection)) return;
4790
         if (!(self && self.peerconnection)) return;
5634
  */
5783
  */
5635
 JingleSessionPC.prototype.addStream = function (stream, callback) {
5784
 JingleSessionPC.prototype.addStream = function (stream, callback) {
5636
 
5785
 
5786
+    var self = this;
5787
+
5637
     // Remember SDP to figure out added/removed SSRCs
5788
     // Remember SDP to figure out added/removed SSRCs
5638
     var oldSdp = null;
5789
     var oldSdp = null;
5639
     if(this.peerconnection) {
5790
     if(this.peerconnection) {
5650
         return;
5801
         return;
5651
     }
5802
     }
5652
 
5803
 
5653
-    self.modifySourcesQueue.push(function() {
5804
+    this.modifySourcesQueue.push(function() {
5654
         console.log('modify sources done');
5805
         console.log('modify sources done');
5655
 
5806
 
5656
         callback();
5807
         callback();
5657
 
5808
 
5658
-        var newSdp = new SDP(this.peerconnection.localDescription.sdp);
5809
+        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
5659
         console.log("SDPs", oldSdp, newSdp);
5810
         console.log("SDPs", oldSdp, newSdp);
5660
-        this.notifyMySSRCUpdate(oldSdp, newSdp);
5811
+        self.notifyMySSRCUpdate(oldSdp, newSdp);
5661
     });
5812
     });
5662
 }
5813
 }
5663
 
5814
 
6008
 
6159
 
6009
 module.exports = JingleSessionPC;
6160
 module.exports = JingleSessionPC;
6010
 
6161
 
6011
-},{"../../service/xmpp/XMPPEvents":75,"../RTC/RTC":12,"../RTC/RTCBrowserType":13,"./JingleSession":19,"./LocalSSRCReplacement":21,"./SDP":22,"./SDPDiffer":23,"./SDPUtil":24,"./TraceablePeerConnection":25,"async":33,"sdp-transform":66}],21:[function(require,module,exports){
6162
+},{"../../service/xmpp/XMPPEvents":76,"../RTC/RTC":13,"../RTC/RTCBrowserType":14,"./JingleSession":20,"./LocalSSRCReplacement":22,"./SDP":23,"./SDPDiffer":24,"./SDPUtil":25,"./TraceablePeerConnection":26,"async":34,"sdp-transform":67}],22:[function(require,module,exports){
6012
 /* global $ */
6163
 /* global $ */
6013
 
6164
 
6014
 /*
6165
 /*
6278
 
6429
 
6279
 module.exports = LocalSSRCReplacement;
6430
 module.exports = LocalSSRCReplacement;
6280
 
6431
 
6281
-},{"../RTC/RTCBrowserType":13,"./SDP":22}],22:[function(require,module,exports){
6432
+},{"../RTC/RTCBrowserType":14,"./SDP":23}],23:[function(require,module,exports){
6282
 /* jshint -W117 */
6433
 /* jshint -W117 */
6283
 var SDPUtil = require("./SDPUtil");
6434
 var SDPUtil = require("./SDPUtil");
6284
 
6435
 
6904
 module.exports = SDP;
7055
 module.exports = SDP;
6905
 
7056
 
6906
 
7057
 
6907
-},{"./SDPUtil":24}],23:[function(require,module,exports){
7058
+},{"./SDPUtil":25}],24:[function(require,module,exports){
6908
 
7059
 
6909
 var SDPUtil = require("./SDPUtil");
7060
 var SDPUtil = require("./SDPUtil");
6910
 
7061
 
7076
 };
7227
 };
7077
 
7228
 
7078
 module.exports = SDPDiffer;
7229
 module.exports = SDPDiffer;
7079
-},{"./SDPUtil":24}],24:[function(require,module,exports){
7230
+},{"./SDPUtil":25}],25:[function(require,module,exports){
7080
 SDPUtil = {
7231
 SDPUtil = {
7081
     filter_special_chars: function (text) {
7232
     filter_special_chars: function (text) {
7082
         return text.replace(/[\\\/\{,\}\+]/g, "");
7233
         return text.replace(/[\\\/\{,\}\+]/g, "");
7429
     }
7580
     }
7430
 };
7581
 };
7431
 module.exports = SDPUtil;
7582
 module.exports = SDPUtil;
7432
-},{}],25:[function(require,module,exports){
7583
+},{}],26:[function(require,module,exports){
7433
 var RTC = require('../RTC/RTC');
7584
 var RTC = require('../RTC/RTC');
7434
 var RTCBrowserType = require("../RTC/RTCBrowserType.js");
7585
 var RTCBrowserType = require("../RTC/RTCBrowserType.js");
7435
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
7586
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
7885
 module.exports = TraceablePeerConnection;
8036
 module.exports = TraceablePeerConnection;
7886
 
8037
 
7887
 
8038
 
7888
-},{"../../service/xmpp/XMPPEvents":75,"../RTC/RTC":12,"../RTC/RTCBrowserType.js":13,"./LocalSSRCReplacement":21,"sdp-interop":52,"sdp-simulcast":59,"sdp-transform":66}],26:[function(require,module,exports){
8039
+},{"../../service/xmpp/XMPPEvents":76,"../RTC/RTC":13,"../RTC/RTCBrowserType.js":14,"./LocalSSRCReplacement":22,"sdp-interop":53,"sdp-simulcast":60,"sdp-transform":67}],27:[function(require,module,exports){
7889
 /* global $, $iq, APP, config, messageHandler,
8040
 /* global $, $iq, APP, config, messageHandler,
7890
  roomName, sessionTerminated, Strophe, Util */
8041
  roomName, sessionTerminated, Strophe, Util */
7891
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
8042
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
8306
 
8457
 
8307
 
8458
 
8308
 
8459
 
8309
-},{"../../service/authentication/AuthenticationEvents":73,"../../service/xmpp/XMPPEvents":75,"../settings/Settings":17}],27:[function(require,module,exports){
8460
+},{"../../service/authentication/AuthenticationEvents":74,"../../service/xmpp/XMPPEvents":76,"../settings/Settings":18}],28:[function(require,module,exports){
8310
 /* jshint -W117 */
8461
 /* jshint -W117 */
8311
 /* a simple MUC connection plugin
8462
 /* a simple MUC connection plugin
8312
  * can only handle a single MUC room
8463
  * can only handle a single MUC room
8399
 };
8550
 };
8400
 
8551
 
8401
 
8552
 
8402
-},{"./ChatRoom":18}],28:[function(require,module,exports){
8553
+},{"./ChatRoom":19}],29:[function(require,module,exports){
8403
 /* jshint -W117 */
8554
 /* jshint -W117 */
8404
 
8555
 
8405
 var JingleSession = require("./JingleSessionPC");
8556
 var JingleSession = require("./JingleSessionPC");
8690
 };
8841
 };
8691
 
8842
 
8692
 
8843
 
8693
-},{"../../service/xmpp/XMPPEvents":75,"../RTC/RTCBrowserType":13,"./JingleSessionPC":20}],29:[function(require,module,exports){
8844
+},{"../../service/xmpp/XMPPEvents":76,"../RTC/RTCBrowserType":14,"./JingleSessionPC":21}],30:[function(require,module,exports){
8694
 /* global Strophe */
8845
 /* global Strophe */
8695
 module.exports = function () {
8846
 module.exports = function () {
8696
 
8847
 
8711
         }
8862
         }
8712
     });
8863
     });
8713
 };
8864
 };
8714
-},{}],30:[function(require,module,exports){
8865
+},{}],31:[function(require,module,exports){
8715
 /* jshint -W117 */
8866
 /* jshint -W117 */
8716
 module.exports = function() {
8867
 module.exports = function() {
8717
     Strophe.addConnectionPlugin('rayo',
8868
     Strophe.addConnectionPlugin('rayo',
8808
     );
8959
     );
8809
 };
8960
 };
8810
 
8961
 
8811
-},{}],31:[function(require,module,exports){
8962
+},{}],32:[function(require,module,exports){
8812
 /**
8963
 /**
8813
  * Strophe logger implementation. Logs from level WARN and above.
8964
  * Strophe logger implementation. Logs from level WARN and above.
8814
  */
8965
  */
8852
     };
9003
     };
8853
 };
9004
 };
8854
 
9005
 
8855
-},{}],32:[function(require,module,exports){
9006
+},{}],33:[function(require,module,exports){
8856
 /* global $, APP, config, Strophe*/
9007
 /* global $, APP, config, Strophe*/
8857
 var EventEmitter = require("events");
9008
 var EventEmitter = require("events");
8858
 var Pako = require("pako");
9009
 var Pako = require("pako");
9148
 
9299
 
9149
 module.exports = XMPP;
9300
 module.exports = XMPP;
9150
 
9301
 
9151
-},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":70,"../../service/RTC/StreamEventTypes":72,"../../service/xmpp/XMPPEvents":75,"../RTC/RTC":12,"./strophe.emuc":27,"./strophe.jingle":28,"./strophe.logger":29,"./strophe.rayo":30,"./strophe.util":31,"events":76,"pako":35}],33:[function(require,module,exports){
9302
+},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":71,"../../service/RTC/StreamEventTypes":73,"../../service/xmpp/XMPPEvents":76,"../RTC/RTC":13,"./strophe.emuc":28,"./strophe.jingle":29,"./strophe.logger":30,"./strophe.rayo":31,"./strophe.util":32,"events":77,"pako":36}],34:[function(require,module,exports){
9152
 (function (process){
9303
 (function (process){
9153
 /*!
9304
 /*!
9154
  * async
9305
  * async
10275
 }());
10426
 }());
10276
 
10427
 
10277
 }).call(this,require('_process'))
10428
 }).call(this,require('_process'))
10278
-},{"_process":77}],34:[function(require,module,exports){
10429
+},{"_process":78}],35:[function(require,module,exports){
10279
 (function (process,global){
10430
 (function (process,global){
10280
 /*!
10431
 /*!
10281
  * @overview es6-promise - a tiny implementation of Promises/A+.
10432
  * @overview es6-promise - a tiny implementation of Promises/A+.
11246
 
11397
 
11247
 
11398
 
11248
 }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
11399
 }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
11249
-},{"_process":77}],35:[function(require,module,exports){
11400
+},{"_process":78}],36:[function(require,module,exports){
11250
 // Top level file is just a mixin of submodules & constants
11401
 // Top level file is just a mixin of submodules & constants
11251
 'use strict';
11402
 'use strict';
11252
 
11403
 
11262
 
11413
 
11263
 module.exports = pako;
11414
 module.exports = pako;
11264
 
11415
 
11265
-},{"./lib/deflate":36,"./lib/inflate":37,"./lib/utils/common":38,"./lib/zlib/constants":41}],36:[function(require,module,exports){
11416
+},{"./lib/deflate":37,"./lib/inflate":38,"./lib/utils/common":39,"./lib/zlib/constants":42}],37:[function(require,module,exports){
11266
 'use strict';
11417
 'use strict';
11267
 
11418
 
11268
 
11419
 
11640
 exports.deflateRaw = deflateRaw;
11791
 exports.deflateRaw = deflateRaw;
11641
 exports.gzip = gzip;
11792
 exports.gzip = gzip;
11642
 
11793
 
11643
-},{"./utils/common":38,"./utils/strings":39,"./zlib/deflate.js":43,"./zlib/messages":48,"./zlib/zstream":50}],37:[function(require,module,exports){
11794
+},{"./utils/common":39,"./utils/strings":40,"./zlib/deflate.js":44,"./zlib/messages":49,"./zlib/zstream":51}],38:[function(require,module,exports){
11644
 'use strict';
11795
 'use strict';
11645
 
11796
 
11646
 
11797
 
12021
 exports.inflateRaw = inflateRaw;
12172
 exports.inflateRaw = inflateRaw;
12022
 exports.ungzip  = inflate;
12173
 exports.ungzip  = inflate;
12023
 
12174
 
12024
-},{"./utils/common":38,"./utils/strings":39,"./zlib/constants":41,"./zlib/gzheader":44,"./zlib/inflate.js":46,"./zlib/messages":48,"./zlib/zstream":50}],38:[function(require,module,exports){
12175
+},{"./utils/common":39,"./utils/strings":40,"./zlib/constants":42,"./zlib/gzheader":45,"./zlib/inflate.js":47,"./zlib/messages":49,"./zlib/zstream":51}],39:[function(require,module,exports){
12025
 'use strict';
12176
 'use strict';
12026
 
12177
 
12027
 
12178
 
12125
 
12276
 
12126
 exports.setTyped(TYPED_OK);
12277
 exports.setTyped(TYPED_OK);
12127
 
12278
 
12128
-},{}],39:[function(require,module,exports){
12279
+},{}],40:[function(require,module,exports){
12129
 // String encode/decode helpers
12280
 // String encode/decode helpers
12130
 'use strict';
12281
 'use strict';
12131
 
12282
 
12312
   return (pos + _utf8len[buf[pos]] > max) ? pos : max;
12463
   return (pos + _utf8len[buf[pos]] > max) ? pos : max;
12313
 };
12464
 };
12314
 
12465
 
12315
-},{"./common":38}],40:[function(require,module,exports){
12466
+},{"./common":39}],41:[function(require,module,exports){
12316
 'use strict';
12467
 'use strict';
12317
 
12468
 
12318
 // Note: adler32 takes 12% for level 0 and 2% for level 6.
12469
 // Note: adler32 takes 12% for level 0 and 2% for level 6.
12346
 
12497
 
12347
 module.exports = adler32;
12498
 module.exports = adler32;
12348
 
12499
 
12349
-},{}],41:[function(require,module,exports){
12500
+},{}],42:[function(require,module,exports){
12350
 module.exports = {
12501
 module.exports = {
12351
 
12502
 
12352
   /* Allowed flush values; see deflate() and inflate() below for details */
12503
   /* Allowed flush values; see deflate() and inflate() below for details */
12395
   //Z_NULL:                 null // Use -1 or null inline, depending on var type
12546
   //Z_NULL:                 null // Use -1 or null inline, depending on var type
12396
 };
12547
 };
12397
 
12548
 
12398
-},{}],42:[function(require,module,exports){
12549
+},{}],43:[function(require,module,exports){
12399
 'use strict';
12550
 'use strict';
12400
 
12551
 
12401
 // Note: we can't get significant speed boost here.
12552
 // Note: we can't get significant speed boost here.
12438
 
12589
 
12439
 module.exports = crc32;
12590
 module.exports = crc32;
12440
 
12591
 
12441
-},{}],43:[function(require,module,exports){
12592
+},{}],44:[function(require,module,exports){
12442
 'use strict';
12593
 'use strict';
12443
 
12594
 
12444
 var utils   = require('../utils/common');
12595
 var utils   = require('../utils/common');
14205
 exports.deflateTune = deflateTune;
14356
 exports.deflateTune = deflateTune;
14206
 */
14357
 */
14207
 
14358
 
14208
-},{"../utils/common":38,"./adler32":40,"./crc32":42,"./messages":48,"./trees":49}],44:[function(require,module,exports){
14359
+},{"../utils/common":39,"./adler32":41,"./crc32":43,"./messages":49,"./trees":50}],45:[function(require,module,exports){
14209
 'use strict';
14360
 'use strict';
14210
 
14361
 
14211
 
14362
 
14247
 
14398
 
14248
 module.exports = GZheader;
14399
 module.exports = GZheader;
14249
 
14400
 
14250
-},{}],45:[function(require,module,exports){
14401
+},{}],46:[function(require,module,exports){
14251
 'use strict';
14402
 'use strict';
14252
 
14403
 
14253
 // See state defs from inflate.js
14404
 // See state defs from inflate.js
14574
   return;
14725
   return;
14575
 };
14726
 };
14576
 
14727
 
14577
-},{}],46:[function(require,module,exports){
14728
+},{}],47:[function(require,module,exports){
14578
 'use strict';
14729
 'use strict';
14579
 
14730
 
14580
 
14731
 
16079
 exports.inflateUndermine = inflateUndermine;
16230
 exports.inflateUndermine = inflateUndermine;
16080
 */
16231
 */
16081
 
16232
 
16082
-},{"../utils/common":38,"./adler32":40,"./crc32":42,"./inffast":45,"./inftrees":47}],47:[function(require,module,exports){
16233
+},{"../utils/common":39,"./adler32":41,"./crc32":43,"./inffast":46,"./inftrees":48}],48:[function(require,module,exports){
16083
 'use strict';
16234
 'use strict';
16084
 
16235
 
16085
 
16236
 
16408
   return 0;
16559
   return 0;
16409
 };
16560
 };
16410
 
16561
 
16411
-},{"../utils/common":38}],48:[function(require,module,exports){
16562
+},{"../utils/common":39}],49:[function(require,module,exports){
16412
 'use strict';
16563
 'use strict';
16413
 
16564
 
16414
 module.exports = {
16565
 module.exports = {
16423
   '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
16574
   '-6':   'incompatible version' /* Z_VERSION_ERROR (-6) */
16424
 };
16575
 };
16425
 
16576
 
16426
-},{}],49:[function(require,module,exports){
16577
+},{}],50:[function(require,module,exports){
16427
 'use strict';
16578
 'use strict';
16428
 
16579
 
16429
 
16580
 
17624
 exports._tr_tally = _tr_tally;
17775
 exports._tr_tally = _tr_tally;
17625
 exports._tr_align = _tr_align;
17776
 exports._tr_align = _tr_align;
17626
 
17777
 
17627
-},{"../utils/common":38}],50:[function(require,module,exports){
17778
+},{"../utils/common":39}],51:[function(require,module,exports){
17628
 'use strict';
17779
 'use strict';
17629
 
17780
 
17630
 
17781
 
17655
 
17806
 
17656
 module.exports = ZStream;
17807
 module.exports = ZStream;
17657
 
17808
 
17658
-},{}],51:[function(require,module,exports){
17809
+},{}],52:[function(require,module,exports){
17659
 module.exports = function arrayEquals(array) {
17810
 module.exports = function arrayEquals(array) {
17660
     // if the other array is a falsy value, return
17811
     // if the other array is a falsy value, return
17661
     if (!array)
17812
     if (!array)
17681
 }
17832
 }
17682
 
17833
 
17683
 
17834
 
17684
-},{}],52:[function(require,module,exports){
17835
+},{}],53:[function(require,module,exports){
17685
 exports.Interop = require('./interop');
17836
 exports.Interop = require('./interop');
17686
 
17837
 
17687
-},{"./interop":53}],53:[function(require,module,exports){
17838
+},{"./interop":54}],54:[function(require,module,exports){
17688
 "use strict";
17839
 "use strict";
17689
 
17840
 
17690
 var transform = require('./transform');
17841
 var transform = require('./transform');
18266
     //#endregion
18417
     //#endregion
18267
 };
18418
 };
18268
 
18419
 
18269
-},{"./array-equals":51,"./transform":54}],54:[function(require,module,exports){
18420
+},{"./array-equals":52,"./transform":55}],55:[function(require,module,exports){
18270
 var transform = require('sdp-transform');
18421
 var transform = require('sdp-transform');
18271
 
18422
 
18272
 exports.write = function(session, opts) {
18423
 exports.write = function(session, opts) {
18365
 };
18516
 };
18366
 
18517
 
18367
 
18518
 
18368
-},{"sdp-transform":56}],55:[function(require,module,exports){
18519
+},{"sdp-transform":57}],56:[function(require,module,exports){
18369
 var grammar = module.exports = {
18520
 var grammar = module.exports = {
18370
   v: [{
18521
   v: [{
18371
       name: 'version',
18522
       name: 'version',
18614
   });
18765
   });
18615
 });
18766
 });
18616
 
18767
 
18617
-},{}],56:[function(require,module,exports){
18768
+},{}],57:[function(require,module,exports){
18618
 var parser = require('./parser');
18769
 var parser = require('./parser');
18619
 var writer = require('./writer');
18770
 var writer = require('./writer');
18620
 
18771
 
18624
 exports.parsePayloads = parser.parsePayloads;
18775
 exports.parsePayloads = parser.parsePayloads;
18625
 exports.parseRemoteCandidates = parser.parseRemoteCandidates;
18776
 exports.parseRemoteCandidates = parser.parseRemoteCandidates;
18626
 
18777
 
18627
-},{"./parser":57,"./writer":58}],57:[function(require,module,exports){
18778
+},{"./parser":58,"./writer":59}],58:[function(require,module,exports){
18628
 var toIntIfInt = function (v) {
18779
 var toIntIfInt = function (v) {
18629
   return String(Number(v)) === v ? Number(v) : v;
18780
   return String(Number(v)) === v ? Number(v) : v;
18630
 };
18781
 };
18719
   return candidates;
18870
   return candidates;
18720
 };
18871
 };
18721
 
18872
 
18722
-},{"./grammar":55}],58:[function(require,module,exports){
18873
+},{"./grammar":56}],59:[function(require,module,exports){
18723
 var grammar = require('./grammar');
18874
 var grammar = require('./grammar');
18724
 
18875
 
18725
 // customized util.format - discards excess arguments and can void middle ones
18876
 // customized util.format - discards excess arguments and can void middle ones
18835
   return sdp.join('\r\n') + '\r\n';
18986
   return sdp.join('\r\n') + '\r\n';
18836
 };
18987
 };
18837
 
18988
 
18838
-},{"./grammar":55}],59:[function(require,module,exports){
18989
+},{"./grammar":56}],60:[function(require,module,exports){
18839
 var transform = require('sdp-transform');
18990
 var transform = require('sdp-transform');
18840
 var transformUtils = require('./transform-utils');
18991
 var transformUtils = require('./transform-utils');
18841
 var parseSsrcs = transformUtils.parseSsrcs;
18992
 var parseSsrcs = transformUtils.parseSsrcs;
19237
 
19388
 
19238
 module.exports = Simulcast;
19389
 module.exports = Simulcast;
19239
 
19390
 
19240
-},{"./transform-utils":60,"sdp-transform":62}],60:[function(require,module,exports){
19391
+},{"./transform-utils":61,"sdp-transform":63}],61:[function(require,module,exports){
19241
 exports.writeSsrcs = function(sources, order) {
19392
 exports.writeSsrcs = function(sources, order) {
19242
   var ssrcs = [];
19393
   var ssrcs = [];
19243
 
19394
 
19288
 };
19439
 };
19289
 
19440
 
19290
 
19441
 
19291
-},{}],61:[function(require,module,exports){
19292
-arguments[4][55][0].apply(exports,arguments)
19293
-},{"dup":55}],62:[function(require,module,exports){
19442
+},{}],62:[function(require,module,exports){
19294
 arguments[4][56][0].apply(exports,arguments)
19443
 arguments[4][56][0].apply(exports,arguments)
19295
-},{"./parser":63,"./writer":64,"dup":56}],63:[function(require,module,exports){
19444
+},{"dup":56}],63:[function(require,module,exports){
19296
 arguments[4][57][0].apply(exports,arguments)
19445
 arguments[4][57][0].apply(exports,arguments)
19297
-},{"./grammar":61,"dup":57}],64:[function(require,module,exports){
19446
+},{"./parser":64,"./writer":65,"dup":57}],64:[function(require,module,exports){
19298
 arguments[4][58][0].apply(exports,arguments)
19447
 arguments[4][58][0].apply(exports,arguments)
19299
-},{"./grammar":61,"dup":58}],65:[function(require,module,exports){
19448
+},{"./grammar":62,"dup":58}],65:[function(require,module,exports){
19449
+arguments[4][59][0].apply(exports,arguments)
19450
+},{"./grammar":62,"dup":59}],66:[function(require,module,exports){
19300
 var grammar = module.exports = {
19451
 var grammar = module.exports = {
19301
   v: [{
19452
   v: [{
19302
       name: 'version',
19453
       name: 'version',
19547
   });
19698
   });
19548
 });
19699
 });
19549
 
19700
 
19550
-},{}],66:[function(require,module,exports){
19551
-arguments[4][56][0].apply(exports,arguments)
19552
-},{"./parser":67,"./writer":68,"dup":56}],67:[function(require,module,exports){
19701
+},{}],67:[function(require,module,exports){
19702
+arguments[4][57][0].apply(exports,arguments)
19703
+},{"./parser":68,"./writer":69,"dup":57}],68:[function(require,module,exports){
19553
 var toIntIfInt = function (v) {
19704
 var toIntIfInt = function (v) {
19554
   return String(Number(v)) === v ? Number(v) : v;
19705
   return String(Number(v)) === v ? Number(v) : v;
19555
 };
19706
 };
19644
   return candidates;
19795
   return candidates;
19645
 };
19796
 };
19646
 
19797
 
19647
-},{"./grammar":65}],68:[function(require,module,exports){
19648
-arguments[4][58][0].apply(exports,arguments)
19649
-},{"./grammar":65,"dup":58}],69:[function(require,module,exports){
19798
+},{"./grammar":66}],69:[function(require,module,exports){
19799
+arguments[4][59][0].apply(exports,arguments)
19800
+},{"./grammar":66,"dup":59}],70:[function(require,module,exports){
19650
 var MediaStreamType = {
19801
 var MediaStreamType = {
19651
     VIDEO_TYPE: "Video",
19802
     VIDEO_TYPE: "Video",
19652
 
19803
 
19653
     AUDIO_TYPE: "Audio"
19804
     AUDIO_TYPE: "Audio"
19654
 };
19805
 };
19655
 module.exports = MediaStreamType;
19806
 module.exports = MediaStreamType;
19656
-},{}],70:[function(require,module,exports){
19807
+},{}],71:[function(require,module,exports){
19657
 var RTCEvents = {
19808
 var RTCEvents = {
19658
     RTC_READY: "rtc.ready",
19809
     RTC_READY: "rtc.ready",
19659
     DATA_CHANNEL_OPEN: "rtc.data_channel_open",
19810
     DATA_CHANNEL_OPEN: "rtc.data_channel_open",
19666
 };
19817
 };
19667
 
19818
 
19668
 module.exports = RTCEvents;
19819
 module.exports = RTCEvents;
19669
-},{}],71:[function(require,module,exports){
19820
+},{}],72:[function(require,module,exports){
19670
 var Resolutions = {
19821
 var Resolutions = {
19671
     "1080": {
19822
     "1080": {
19672
         width: 1920,
19823
         width: 1920,
19720
     }
19871
     }
19721
 };
19872
 };
19722
 module.exports = Resolutions;
19873
 module.exports = Resolutions;
19723
-},{}],72:[function(require,module,exports){
19874
+},{}],73:[function(require,module,exports){
19724
 var StreamEventTypes = {
19875
 var StreamEventTypes = {
19725
     EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
19876
     EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
19726
 
19877
 
19734
 };
19885
 };
19735
 
19886
 
19736
 module.exports = StreamEventTypes;
19887
 module.exports = StreamEventTypes;
19737
-},{}],73:[function(require,module,exports){
19888
+},{}],74:[function(require,module,exports){
19738
 var AuthenticationEvents = {
19889
 var AuthenticationEvents = {
19739
     /**
19890
     /**
19740
      * Event callback arguments:
19891
      * Event callback arguments:
19748
 };
19899
 };
19749
 module.exports = AuthenticationEvents;
19900
 module.exports = AuthenticationEvents;
19750
 
19901
 
19751
-},{}],74:[function(require,module,exports){
19902
+},{}],75:[function(require,module,exports){
19752
 var DesktopSharingEventTypes = {
19903
 var DesktopSharingEventTypes = {
19753
     INIT: "ds.init",
19904
     INIT: "ds.init",
19754
 
19905
 
19758
 };
19909
 };
19759
 
19910
 
19760
 module.exports = DesktopSharingEventTypes;
19911
 module.exports = DesktopSharingEventTypes;
19761
-},{}],75:[function(require,module,exports){
19912
+},{}],76:[function(require,module,exports){
19762
 var XMPPEvents = {
19913
 var XMPPEvents = {
19763
     CONNECTION_FAILED: "xmpp.connection.failed",
19914
     CONNECTION_FAILED: "xmpp.connection.failed",
19764
     // Indicates an interrupted connection event.
19915
     // Indicates an interrupted connection event.
19815
     REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received"
19966
     REMOTE_STREAM_RECEIVED: "xmpp.remote_stream_received"
19816
 };
19967
 };
19817
 module.exports = XMPPEvents;
19968
 module.exports = XMPPEvents;
19818
-},{}],76:[function(require,module,exports){
19969
+},{}],77:[function(require,module,exports){
19819
 // Copyright Joyent, Inc. and other Node contributors.
19970
 // Copyright Joyent, Inc. and other Node contributors.
19820
 //
19971
 //
19821
 // Permission is hereby granted, free of charge, to any person obtaining a
19972
 // Permission is hereby granted, free of charge, to any person obtaining a
20118
   return arg === void 0;
20269
   return arg === void 0;
20119
 }
20270
 }
20120
 
20271
 
20121
-},{}],77:[function(require,module,exports){
20272
+},{}],78:[function(require,module,exports){
20122
 // shim for using process in browser
20273
 // shim for using process in browser
20123
 
20274
 
20124
 var process = module.exports = {};
20275
 var process = module.exports = {};

+ 0
- 21
modules/RTC/JitsiLocalTrack.js 查看文件

1
 var JitsiTrack = require("./JitsiTrack");
1
 var JitsiTrack = require("./JitsiTrack");
2
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
2
 var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
3
 var RTCEvents = require("../../service/RTC/RTCEvents");
3
 var RTCEvents = require("../../service/RTC/RTCEvents");
4
-var RTCBrowserType = require("./RTCBrowserType");
5
-
6
-/**
7
- * This implements 'onended' callback normally fired by WebRTC after the stream
8
- * is stopped. There is no such behaviour yet in FF, so we have to add it.
9
- * @param stream original WebRTC stream object to which 'onended' handling
10
- *               will be added.
11
- */
12
-function implementOnEndedHandling(stream) {
13
-    var originalStop = stream.stop;
14
-    stream.stop = function () {
15
-        originalStop.apply(stream);
16
-        if (!stream.ended) {
17
-            stream.ended = true;
18
-            stream.onended();
19
-        }
20
-    };
21
-}
22
 
4
 
23
 /**
5
 /**
24
  * Represents a single media track (either audio or video).
6
  * Represents a single media track (either audio or video).
35
     this.stream.onended = function () {
17
     this.stream.onended = function () {
36
         this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
18
         this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
37
     }.bind(this);
19
     }.bind(this);
38
-    if (RTCBrowserType.isFirefox()) {
39
-        implementOnEndedHandling(this.stream);
40
-    }
41
 }
20
 }
42
 
21
 
43
 JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);
22
 JitsiLocalTrack.prototype = Object.create(JitsiTrack.prototype);

+ 6
- 0
modules/RTC/JitsiRemoteTrack.js 查看文件

1
 var JitsiTrack = require("./JitsiTrack");
1
 var JitsiTrack = require("./JitsiTrack");
2
+var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
2
 
3
 
3
 /**
4
 /**
4
  * Represents a single media track (either audio or video).
5
  * Represents a single media track (either audio or video).
14
     this.ssrc = ssrc;
15
     this.ssrc = ssrc;
15
     this.muted = false;
16
     this.muted = false;
16
     this.eventEmitter = eventEmitter;
17
     this.eventEmitter = eventEmitter;
18
+    var self = this;
19
+    if(this.stream)
20
+        this.stream.onended = function () {
21
+            eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, self);
22
+        }
17
 }
23
 }
18
 
24
 
19
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
25
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);

+ 21
- 0
modules/RTC/JitsiTrack.js 查看文件

1
 var RTC = require("./RTCUtils");
1
 var RTC = require("./RTCUtils");
2
+var RTCBrowserType = require("./RTCBrowserType");
3
+
4
+/**
5
+ * This implements 'onended' callback normally fired by WebRTC after the stream
6
+ * is stopped. There is no such behaviour yet in FF, so we have to add it.
7
+ * @param stream original WebRTC stream object to which 'onended' handling
8
+ *               will be added.
9
+ */
10
+function implementOnEndedHandling(stream) {
11
+    var originalStop = stream.stop;
12
+    stream.stop = function () {
13
+        originalStop.apply(stream);
14
+        if (!stream.ended) {
15
+            stream.ended = true;
16
+            stream.onended();
17
+        }
18
+    };
19
+}
2
 
20
 
3
 /**
21
 /**
4
  * Represents a single media track (either audio or video).
22
  * Represents a single media track (either audio or video).
19
             return this.stream.getVideoTracks();
37
             return this.stream.getVideoTracks();
20
         }.bind(this);
38
         }.bind(this);
21
     }
39
     }
40
+    if (RTCBrowserType.isFirefox() && this.stream) {
41
+        implementOnEndedHandling(this.stream);
42
+    }
22
 }
43
 }
23
 
44
 
24
 /**
45
 /**

正在加载...
取消
保存