Browse Source

Fixes the issues with mute, audio levels and remove events that were attached to the conference

master
hristoterezov 9 years ago
parent
commit
8409bab854

+ 80
- 44
JitsiConference.js View File

@@ -2,12 +2,12 @@
2 2
 var logger = require("jitsi-meet-logger").getLogger(__filename);
3 3
 var RTC = require("./modules/RTC/RTC");
4 4
 var XMPPEvents = require("./service/xmpp/XMPPEvents");
5
-var StreamEventTypes = require("./service/RTC/StreamEventTypes");
6 5
 var RTCEvents = require("./service/RTC/RTCEvents");
7 6
 var EventEmitter = require("events");
8 7
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
9 8
 var JitsiParticipant = require("./JitsiParticipant");
10 9
 var Statistics = require("./modules/statistics/statistics");
10
+var JitsiTrackEvents = require("./JitsiTrackEvents");
11 11
 
12 12
 /**
13 13
  * Creates a JitsiConference object with the given name and properties.
@@ -32,7 +32,7 @@ function JitsiConference(options) {
32 32
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
33 33
     this.room.updateDeviceAvailability(RTC.getDeviceAvailability());
34 34
     this.rtc = new RTC(this.room, options);
35
-    if(!options.config.disableAudioLevels)
35
+    if(!RTC.options.disableAudioLevels)
36 36
         this.statistics = new Statistics();
37 37
     setupListeners(this);
38 38
     this.participants = {};
@@ -88,15 +88,16 @@ JitsiConference.prototype.on = function (eventId, handler) {
88 88
  */
89 89
 JitsiConference.prototype.off = function (eventId, handler) {
90 90
     if(this.eventEmitter)
91
-        this.eventEmitter.removeListener(eventId, listener);
91
+        this.eventEmitter.removeListener(eventId, handler);
92 92
 }
93 93
 
94 94
 // Common aliases for event emitter
95
-JitsiConference.prototype.addEventListener = JitsiConference.prototype.on
96
-JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off
95
+JitsiConference.prototype.addEventListener = JitsiConference.prototype.on;
96
+JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;
97 97
 
98 98
 /**
99
- * Receives notifications from another participants for commands / custom events(send by sendPresenceCommand method).
99
+ * Receives notifications from another participants for commands / custom events
100
+ * (send by sendPresenceCommand method).
100 101
  * @param command {String} the name of the command
101 102
  * @param handler {Function} handler for the command
102 103
  */
@@ -172,17 +173,55 @@ JitsiConference.prototype.setDisplayName = function(name) {
172 173
  * @param track the JitsiLocalTrack object.
173 174
  */
174 175
 JitsiConference.prototype.addTrack = function (track) {
175
-    this.rtc.addLocalStream(track);
176
-    this.room.addStream(track.getOriginalStream(), function () {});
176
+    this.room.addStream(track.getOriginalStream(), function () {
177
+        this.rtc.addLocalStream(track);
178
+        var muteHandler = this._fireMuteChangeEvent.bind(this, track);
179
+        var stopHandler = this.removeTrack.bind(this, track);
180
+        var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
181
+        track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
182
+        track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
183
+        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
184
+            audioLevelHandler);
185
+        this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (track) {
186
+            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
187
+                muteHandler);
188
+            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED,
189
+                stopHandler);
190
+            track.removeEventListener(
191
+                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
192
+        })
193
+        this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
194
+    }.bind(this));
195
+
196
+}
197
+
198
+/**
199
+ * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event.
200
+ * @param audioLevel the audio level
201
+ */
202
+JitsiConference.prototype._fireAudioLevelChangeEvent = function (audioLevel) {
203
+    this.eventEmitter.emit(
204
+        JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
205
+        this.myUserId(), audioLevel);
177 206
 }
178 207
 
208
+/**
209
+ * Fires TRACK_MUTE_CHANGED change conference event.
210
+ * @param track the JitsiTrack object related to the event.
211
+ */
212
+JitsiConference.prototype._fireMuteChangeEvent = function (track) {
213
+    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
214
+};
215
+
179 216
 /**
180 217
  * Removes JitsiLocalTrack object to the conference.
181 218
  * @param track the JitsiLocalTrack object.
182 219
  */
183 220
 JitsiConference.prototype.removeTrack = function (track) {
184
-    this.room.removeStream(track.getOriginalStream());
185
-    this.rtc.removeLocalStream(track);
221
+    this.room.removeStream(track.getOriginalStream(), function(){
222
+        this.rtc.removeLocalStream(track);
223
+        this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
224
+    }.bind(this));
186 225
 }
187 226
 
188 227
 /**
@@ -247,8 +286,33 @@ function setupListeners(conference) {
247 286
         if(conference.statistics)
248 287
             conference.statistics.startRemoteStats(event.peerconnection);
249 288
     });
289
+
250 290
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
251
-        conference.rtc.createRemoteStream.bind(conference.rtc));
291
+        function (data, sid, thessrc) {
292
+            var track = conference.rtc.createRemoteStream(data, sid, thessrc);
293
+            if(!track)
294
+                return;
295
+            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED,
296
+                track);
297
+            track.addEventListener(JitsiTrackEvents.TRACK_STOPPED,
298
+                function () {
299
+                    conference.eventEmitter.emit(
300
+                        JitsiConferenceEvents.TRACK_REMOVED, track);
301
+                });
302
+            track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
303
+                function () {
304
+                    conference.eventEmitter.emit(
305
+                        JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
306
+                });
307
+            var userId = track.getParitcipantId();
308
+            track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
309
+                function (audioLevel) {
310
+                    conference.eventEmitter.emit(
311
+                        JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
312
+                        userId, audioLevel);
313
+                });
314
+        }
315
+    );
252 316
 
253 317
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
254 318
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
@@ -285,25 +349,6 @@ function setupListeners(conference) {
285 349
         conference.eventEmitter.emit(JitsiConferenceEvents.SETUP_FAILED);
286 350
     });
287 351
 
288
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED,
289
-        function (stream) {
290
-            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
291
-        });
292
-
293
-//FIXME: Maybe remove event should not be associated with the conference.
294
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, function (stream) {
295
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
296
-    });
297
-//FIXME: Maybe remove event should not be associated with the conference.
298
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, function (stream) {
299
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
300
-        conference.removeTrack(stream);
301
-    });
302
-
303
-    conference.rtc.addListener(StreamEventTypes.TRACK_MUTE_CHANGED, function (track) {
304
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
305
-    });
306
-
307 352
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
308 353
         if(conference.lastActiveSpeaker !== id && conference.room) {
309 354
             conference.lastActiveSpeaker = id;
@@ -325,20 +370,11 @@ function setupListeners(conference) {
325 370
         //FIXME: Maybe remove event should not be associated with the conference.
326 371
         conference.statistics.addAudioLevelListener(function (ssrc, level) {
327 372
             var userId = null;
328
-            if (ssrc === Statistics.LOCAL_JID) {
329
-                userId = conference.myUserId();
330
-            } else {
331
-                var jid = conference.room.getJidBySSRC(ssrc);
332
-                if (!jid)
333
-                    return;
334
-
335
-                userId = Strophe.getResourceFromJid(jid);
336
-            }
337
-            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
338
-                userId, level);
339
-        });
340
-        conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_CREATED, function (stream) {
341
-            conference.statistics.startLocalStats(stream);
373
+            var jid = conference.room.getJidBySSRC(ssrc);
374
+            if (!jid)
375
+                return;
376
+
377
+            conference.rtc.setAudioLevel(jid, level);
342 378
         });
343 379
         conference.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE,
344 380
             function () {

+ 21
- 2
JitsiMeetJS.js View File

@@ -7,6 +7,7 @@ var JitsiTrackEvents = require("./JitsiTrackEvents");
7 7
 var JitsiTrackErrors = require("./JitsiTrackErrors");
8 8
 var Logger = require("jitsi-meet-logger");
9 9
 var RTC = require("./modules/RTC/RTC");
10
+var Statistics = require("./modules/statistics/statistics");
10 11
 
11 12
 /**
12 13
  * Namespace for the interface of Jitsi Meet Library.
@@ -42,11 +43,29 @@ var LibJitsiMeet = {
42 43
      * will be returned trough the Promise, otherwise JitsiTrack objects will be returned.
43 44
      * @param {string} options.cameraDeviceId
44 45
      * @param {string} options.micDeviceId
45
-     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>} A promise that returns an array of created JitsiTracks if resolved,
46
+     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>}
47
+     *     A promise that returns an array of created JitsiTracks if resolved,
46 48
      *     or a JitsiConferenceError if rejected.
47 49
      */
48 50
     createLocalTracks: function (options) {
49
-        return RTC.obtainAudioAndVideoPermissions(options || {});
51
+        return RTC.obtainAudioAndVideoPermissions(options || {}).then(
52
+            function(tracks) {
53
+                if(!RTC.options.disableAudioLevels)
54
+                    for(var i = 0; i < tracks.length; i++) {
55
+                        var track = tracks[i];
56
+                        var mStream = track.getOriginalStream();
57
+                        if(track.getType() === "audio"){
58
+                            Statistics.startLocalStats(mStream,
59
+                                track.setAudioLevel.bind(track));
60
+                            track.addEventListener(
61
+                                JitsiTrackEvents.TRACK_STOPPED,
62
+                                function(){
63
+                                    Statistics.stopLocalStats(mStream);
64
+                                });
65
+                        }
66
+                    }
67
+                return tracks;
68
+            });
50 69
     },
51 70
     isDeviceListAvailable: function () {
52 71
         return RTC.isDeviceListAvailable();

+ 2
- 1
JitsiTrackErrors.js View File

@@ -1,6 +1,7 @@
1 1
 module.exports = {
2 2
     /**
3
-     * Returns JitsiTrackErrors based on the error object passed by GUM * @param error the error
3
+     * Returns JitsiTrackErrors based on the error object passed by GUM
4
+     * @param error the error
4 5
      * @param {Object} options the options object given to GUM.
5 6
      */
6 7
     parseError: function (error, options) {

+ 1
- 1
JitsiTrackEvents.js View File

@@ -10,7 +10,7 @@ var JitsiTrackEvents = {
10 10
     /**
11 11
      * The media track was removed to the conference.
12 12
      */
13
-    TRACK_STOPPED: "track.TRACK_STOPPED",
13
+    TRACK_STOPPED: "track.stopped"
14 14
 };
15 15
 
16 16
 module.exports = JitsiTrackEvents;

+ 31
- 6
doc/example/example.js View File

@@ -9,8 +9,7 @@ var options = {
9 9
 }
10 10
 
11 11
 var confOptions = {
12
-    openSctp: true,
13
-    disableAudioLevels: true
12
+    openSctp: true
14 13
 }
15 14
 
16 15
 /**
@@ -22,6 +21,18 @@ function onLocalTracks(tracks)
22 21
     localTracks = tracks;
23 22
     for(var i = 0; i < localTracks.length; i++)
24 23
     {
24
+        localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
25
+            function (audioLevel) {
26
+                console.debug("Audio Level local: " + audioLevel);
27
+            });
28
+        localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
29
+            function () {
30
+                console.debug("local track muted");
31
+            });
32
+        localTracks[i].addEventListener(JitsiMeetJS.events.track.TRACK_STOPPED,
33
+            function () {
34
+                console.debug("local track stoped");
35
+            });
25 36
         if(localTracks[i].getType() == "video") {
26 37
             $("body").append("<video autoplay='1' id='localVideo" + i + "' />");
27 38
             localTracks[i].attach($("#localVideo" + i ));
@@ -29,7 +40,6 @@ function onLocalTracks(tracks)
29 40
             $("body").append("<audio autoplay='1' id='localAudio" + i + "' />");
30 41
             localTracks[i].attach($("#localAudio" + i ));
31 42
         }
32
-        console.log(localTracks[i]);
33 43
     }
34 44
 }
35 45
 
@@ -38,10 +48,24 @@ function onLocalTracks(tracks)
38 48
  * @param track JitsiTrack object
39 49
  */
40 50
 function onRemoteTrack(track) {
51
+    if(track.isLocal())
52
+        return;
41 53
     var participant = track.getParitcipantId();
42 54
     if(!remoteTracks[participant])
43 55
         remoteTracks[participant] = [];
44 56
     var idx = remoteTracks[participant].push(track);
57
+    track.addEventListener(JitsiMeetJS.events.track.TRACK_AUDIO_LEVEL_CHANGED,
58
+        function (audioLevel) {
59
+            console.debug("Audio Level remote: " + audioLevel);
60
+        });
61
+    track.addEventListener(JitsiMeetJS.events.track.TRACK_MUTE_CHANGED,
62
+        function () {
63
+            console.debug("remote track muted");
64
+        });
65
+    track.addEventListener(JitsiMeetJS.events.track.TRACK_STOPPED,
66
+        function () {
67
+            console.debug("remote track stoped");
68
+        });
45 69
     var id = participant + track.getType() + idx;
46 70
     if(track.getType() == "video") {
47 71
         $("body").append("<video autoplay='1' id='" + participant + "video" + idx + "' />");
@@ -74,8 +98,8 @@ function onUserLeft(id) {
74 98
 function onConnectionSuccess(){
75 99
     room = connection.initJitsiConference("conference2", confOptions);
76 100
     room.on(JitsiMeetJS.events.conference.TRACK_ADDED, onRemoteTrack);
77
-    room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function () {
78
-        console.debug("track removed!!!");
101
+    room.on(JitsiMeetJS.events.conference.TRACK_REMOVED, function (track) {
102
+        console.debug("track removed!!!" + track);
79 103
     });
80 104
     room.on(JitsiMeetJS.events.conference.CONFERENCE_JOINED, onConferenceJoined);
81 105
     room.on(JitsiMeetJS.events.conference.USER_JOINED, function(id){ remoteTracks[id] = [];});
@@ -88,7 +112,7 @@ function onConnectionSuccess(){
88 112
     });
89 113
     room.on(JitsiMeetJS.events.conference.TRACK_AUDIO_LEVEL_CHANGED,
90 114
       function(userID, audioLevel){
91
-          // console.log(userID + " - " + audioLevel);
115
+          console.log(userID + " - " + audioLevel);
92 116
       });
93 117
     room.join();
94 118
 };
@@ -120,6 +144,7 @@ $(window).bind('unload', unload);
120 144
 
121 145
 // JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
122 146
 var initOptions = {
147
+    // disableAudioLevels: true,
123 148
     // Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
124 149
     desktopSharingChromeMethod: 'ext',
125 150
     // The ID of the jidesha extension for Chrome.

+ 283
- 195
lib-jitsi-meet.js View File

@@ -4,12 +4,12 @@
4 4
 var logger = require("jitsi-meet-logger").getLogger(__filename);
5 5
 var RTC = require("./modules/RTC/RTC");
6 6
 var XMPPEvents = require("./service/xmpp/XMPPEvents");
7
-var StreamEventTypes = require("./service/RTC/StreamEventTypes");
8 7
 var RTCEvents = require("./service/RTC/RTCEvents");
9 8
 var EventEmitter = require("events");
10 9
 var JitsiConferenceEvents = require("./JitsiConferenceEvents");
11 10
 var JitsiParticipant = require("./JitsiParticipant");
12 11
 var Statistics = require("./modules/statistics/statistics");
12
+var JitsiTrackEvents = require("./JitsiTrackEvents");
13 13
 
14 14
 /**
15 15
  * Creates a JitsiConference object with the given name and properties.
@@ -34,7 +34,7 @@ function JitsiConference(options) {
34 34
     this.room = this.xmpp.createRoom(this.options.name, null, null, this.options.config);
35 35
     this.room.updateDeviceAvailability(RTC.getDeviceAvailability());
36 36
     this.rtc = new RTC(this.room, options);
37
-    if(!options.config.disableAudioLevels)
37
+    if(!RTC.options.disableAudioLevels)
38 38
         this.statistics = new Statistics();
39 39
     setupListeners(this);
40 40
     this.participants = {};
@@ -90,15 +90,16 @@ JitsiConference.prototype.on = function (eventId, handler) {
90 90
  */
91 91
 JitsiConference.prototype.off = function (eventId, handler) {
92 92
     if(this.eventEmitter)
93
-        this.eventEmitter.removeListener(eventId, listener);
93
+        this.eventEmitter.removeListener(eventId, handler);
94 94
 }
95 95
 
96 96
 // Common aliases for event emitter
97
-JitsiConference.prototype.addEventListener = JitsiConference.prototype.on
98
-JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off
97
+JitsiConference.prototype.addEventListener = JitsiConference.prototype.on;
98
+JitsiConference.prototype.removeEventListener = JitsiConference.prototype.off;
99 99
 
100 100
 /**
101
- * Receives notifications from another participants for commands / custom events(send by sendPresenceCommand method).
101
+ * Receives notifications from another participants for commands / custom events
102
+ * (send by sendPresenceCommand method).
102 103
  * @param command {String} the name of the command
103 104
  * @param handler {Function} handler for the command
104 105
  */
@@ -174,17 +175,55 @@ JitsiConference.prototype.setDisplayName = function(name) {
174 175
  * @param track the JitsiLocalTrack object.
175 176
  */
176 177
 JitsiConference.prototype.addTrack = function (track) {
177
-    this.rtc.addLocalStream(track);
178
-    this.room.addStream(track.getOriginalStream(), function () {});
178
+    this.room.addStream(track.getOriginalStream(), function () {
179
+        this.rtc.addLocalStream(track);
180
+        var muteHandler = this._fireMuteChangeEvent.bind(this, track);
181
+        var stopHandler = this.removeTrack.bind(this, track);
182
+        var audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
183
+        track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED, muteHandler);
184
+        track.addEventListener(JitsiTrackEvents.TRACK_STOPPED, stopHandler);
185
+        track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
186
+            audioLevelHandler);
187
+        this.addEventListener(JitsiConferenceEvents.TRACK_REMOVED, function (track) {
188
+            track.removeEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
189
+                muteHandler);
190
+            track.removeEventListener(JitsiTrackEvents.TRACK_STOPPED,
191
+                stopHandler);
192
+            track.removeEventListener(
193
+                JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED, audioLevelHandler);
194
+        })
195
+        this.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, track);
196
+    }.bind(this));
197
+
198
+}
199
+
200
+/**
201
+ * Fires TRACK_AUDIO_LEVEL_CHANGED change conference event.
202
+ * @param audioLevel the audio level
203
+ */
204
+JitsiConference.prototype._fireAudioLevelChangeEvent = function (audioLevel) {
205
+    this.eventEmitter.emit(
206
+        JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
207
+        this.myUserId(), audioLevel);
179 208
 }
180 209
 
210
+/**
211
+ * Fires TRACK_MUTE_CHANGED change conference event.
212
+ * @param track the JitsiTrack object related to the event.
213
+ */
214
+JitsiConference.prototype._fireMuteChangeEvent = function (track) {
215
+    this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
216
+};
217
+
181 218
 /**
182 219
  * Removes JitsiLocalTrack object to the conference.
183 220
  * @param track the JitsiLocalTrack object.
184 221
  */
185 222
 JitsiConference.prototype.removeTrack = function (track) {
186
-    this.room.removeStream(track.getOriginalStream());
187
-    this.rtc.removeLocalStream(track);
223
+    this.room.removeStream(track.getOriginalStream(), function(){
224
+        this.rtc.removeLocalStream(track);
225
+        this.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, track);
226
+    }.bind(this));
188 227
 }
189 228
 
190 229
 /**
@@ -249,8 +288,33 @@ function setupListeners(conference) {
249 288
         if(conference.statistics)
250 289
             conference.statistics.startRemoteStats(event.peerconnection);
251 290
     });
291
+
252 292
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
253
-        conference.rtc.createRemoteStream.bind(conference.rtc));
293
+        function (data, sid, thessrc) {
294
+            var track = conference.rtc.createRemoteStream(data, sid, thessrc);
295
+            if(!track)
296
+                return;
297
+            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED,
298
+                track);
299
+            track.addEventListener(JitsiTrackEvents.TRACK_STOPPED,
300
+                function () {
301
+                    conference.eventEmitter.emit(
302
+                        JitsiConferenceEvents.TRACK_REMOVED, track);
303
+                });
304
+            track.addEventListener(JitsiTrackEvents.TRACK_MUTE_CHANGED,
305
+                function () {
306
+                    conference.eventEmitter.emit(
307
+                        JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
308
+                });
309
+            var userId = track.getParitcipantId();
310
+            track.addEventListener(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
311
+                function (audioLevel) {
312
+                    conference.eventEmitter.emit(
313
+                        JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
314
+                        userId, audioLevel);
315
+                });
316
+        }
317
+    );
254 318
 
255 319
     conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
256 320
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_JOINED);
@@ -287,25 +351,6 @@ function setupListeners(conference) {
287 351
         conference.eventEmitter.emit(JitsiConferenceEvents.SETUP_FAILED);
288 352
     });
289 353
 
290
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED,
291
-        function (stream) {
292
-            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_ADDED, stream);
293
-        });
294
-
295
-//FIXME: Maybe remove event should not be associated with the conference.
296
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, function (stream) {
297
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
298
-    });
299
-//FIXME: Maybe remove event should not be associated with the conference.
300
-    conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, function (stream) {
301
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_REMOVED, stream);
302
-        conference.removeTrack(stream);
303
-    });
304
-
305
-    conference.rtc.addListener(StreamEventTypes.TRACK_MUTE_CHANGED, function (track) {
306
-        conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track);
307
-    });
308
-
309 354
     conference.rtc.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (id) {
310 355
         if(conference.lastActiveSpeaker !== id && conference.room) {
311 356
             conference.lastActiveSpeaker = id;
@@ -327,20 +372,11 @@ function setupListeners(conference) {
327 372
         //FIXME: Maybe remove event should not be associated with the conference.
328 373
         conference.statistics.addAudioLevelListener(function (ssrc, level) {
329 374
             var userId = null;
330
-            if (ssrc === Statistics.LOCAL_JID) {
331
-                userId = conference.myUserId();
332
-            } else {
333
-                var jid = conference.room.getJidBySSRC(ssrc);
334
-                if (!jid)
335
-                    return;
375
+            var jid = conference.room.getJidBySSRC(ssrc);
376
+            if (!jid)
377
+                return;
336 378
 
337
-                userId = Strophe.getResourceFromJid(jid);
338
-            }
339
-            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
340
-                userId, level);
341
-        });
342
-        conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_CREATED, function (stream) {
343
-            conference.statistics.startLocalStats(stream);
379
+            conference.rtc.setAudioLevel(jid, level);
344 380
         });
345 381
         conference.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE,
346 382
             function () {
@@ -357,7 +393,7 @@ function setupListeners(conference) {
357 393
 module.exports = JitsiConference;
358 394
 
359 395
 }).call(this,"/JitsiConference.js")
360
-},{"./JitsiConferenceEvents":3,"./JitsiParticipant":8,"./modules/RTC/RTC":15,"./modules/statistics/statistics":23,"./service/RTC/RTCEvents":82,"./service/RTC/StreamEventTypes":84,"./service/xmpp/XMPPEvents":89,"events":42,"jitsi-meet-logger":46}],2:[function(require,module,exports){
396
+},{"./JitsiConferenceEvents":3,"./JitsiParticipant":8,"./JitsiTrackEvents":10,"./modules/RTC/RTC":15,"./modules/statistics/statistics":23,"./service/RTC/RTCEvents":82,"./service/xmpp/XMPPEvents":88,"events":42,"jitsi-meet-logger":46}],2:[function(require,module,exports){
361 397
 /**
362 398
  * Enumeration with the errors for the conference.
363 399
  * @type {{string: string}}
@@ -627,6 +663,7 @@ var JitsiTrackEvents = require("./JitsiTrackEvents");
627 663
 var JitsiTrackErrors = require("./JitsiTrackErrors");
628 664
 var Logger = require("jitsi-meet-logger");
629 665
 var RTC = require("./modules/RTC/RTC");
666
+var Statistics = require("./modules/statistics/statistics");
630 667
 
631 668
 /**
632 669
  * Namespace for the interface of Jitsi Meet Library.
@@ -662,11 +699,29 @@ var LibJitsiMeet = {
662 699
      * will be returned trough the Promise, otherwise JitsiTrack objects will be returned.
663 700
      * @param {string} options.cameraDeviceId
664 701
      * @param {string} options.micDeviceId
665
-     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>} A promise that returns an array of created JitsiTracks if resolved,
702
+     * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>}
703
+     *     A promise that returns an array of created JitsiTracks if resolved,
666 704
      *     or a JitsiConferenceError if rejected.
667 705
      */
668 706
     createLocalTracks: function (options) {
669
-        return RTC.obtainAudioAndVideoPermissions(options || {});
707
+        return RTC.obtainAudioAndVideoPermissions(options || {}).then(
708
+            function(tracks) {
709
+                if(!RTC.options.disableAudioLevels)
710
+                    for(var i = 0; i < tracks.length; i++) {
711
+                        var track = tracks[i];
712
+                        var mStream = track.getOriginalStream();
713
+                        if(track.getType() === "audio"){
714
+                            Statistics.startLocalStats(mStream,
715
+                                track.setAudioLevel.bind(track));
716
+                            track.addEventListener(
717
+                                JitsiTrackEvents.TRACK_STOPPED,
718
+                                function(){
719
+                                    Statistics.stopLocalStats(mStream);
720
+                                });
721
+                        }
722
+                    }
723
+                return tracks;
724
+            });
670 725
     },
671 726
     isDeviceListAvailable: function () {
672 727
         return RTC.isDeviceListAvailable();
@@ -682,7 +737,7 @@ window.Promise = window.Promise || require("es6-promise").Promise;
682 737
 
683 738
 module.exports = LibJitsiMeet;
684 739
 
685
-},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./JitsiTrackErrors":9,"./JitsiTrackEvents":10,"./modules/RTC/RTC":15,"es6-promise":44,"jitsi-meet-logger":46}],8:[function(require,module,exports){
740
+},{"./JitsiConferenceErrors":2,"./JitsiConferenceEvents":3,"./JitsiConnection":4,"./JitsiConnectionErrors":5,"./JitsiConnectionEvents":6,"./JitsiTrackErrors":9,"./JitsiTrackEvents":10,"./modules/RTC/RTC":15,"./modules/statistics/statistics":23,"es6-promise":44,"jitsi-meet-logger":46}],8:[function(require,module,exports){
686 741
 /**
687 742
  * Represents a participant in (a member of) a conference.
688 743
  */
@@ -823,7 +878,8 @@ module.exports = JitsiParticipant();
823 878
 },{}],9:[function(require,module,exports){
824 879
 module.exports = {
825 880
     /**
826
-     * Returns JitsiTrackErrors based on the error object passed by GUM * @param error the error
881
+     * Returns JitsiTrackErrors based on the error object passed by GUM
882
+     * @param error the error
827 883
      * @param {Object} options the options object given to GUM.
828 884
      */
829 885
     parseError: function (error, options) {
@@ -858,7 +914,7 @@ var JitsiTrackEvents = {
858 914
     /**
859 915
      * The media track was removed to the conference.
860 916
      */
861
-    TRACK_STOPPED: "track.TRACK_STOPPED",
917
+    TRACK_STOPPED: "track.stopped"
862 918
 };
863 919
 
864 920
 module.exports = JitsiTrackEvents;
@@ -1081,8 +1137,8 @@ module.exports = DataChannels;
1081 1137
 }).call(this,"/modules/RTC/DataChannels.js")
1082 1138
 },{"../../service/RTC/RTCEvents":82,"jitsi-meet-logger":46}],12:[function(require,module,exports){
1083 1139
 var JitsiTrack = require("./JitsiTrack");
1084
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
1085 1140
 var RTCBrowserType = require("./RTCBrowserType");
1141
+var JitsiTrackEvents = require('../../JitsiTrackEvents');
1086 1142
 var RTC = require("./RTCUtils");
1087 1143
 
1088 1144
 /**
@@ -1095,14 +1151,15 @@ function JitsiLocalTrack(stream, videoType,
1095 1151
     this.videoType = videoType;
1096 1152
     this.dontFireRemoveEvent = false;
1097 1153
     this.resolution = resolution;
1154
+    this.startMuted = false;
1098 1155
     var self = this;
1099 1156
     JitsiTrack.call(this, null, stream,
1100 1157
         function () {
1101
-            if(!self.dontFireRemoveEvent && self.rtc)
1102
-                self.rtc.eventEmitter.emit(
1103
-                    StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, self);
1104
-            self.dontFireRemoveEvent = false;
1105
-        });
1158
+            if(!this.dontFireRemoveEvent)
1159
+                this.eventEmitter.emit(
1160
+                    JitsiTrackEvents.TRACK_STOPPED);
1161
+            this.dontFireRemoveEvent = false;
1162
+        }.bind(this));
1106 1163
 
1107 1164
 }
1108 1165
 
@@ -1115,14 +1172,14 @@ JitsiLocalTrack.prototype.constructor = JitsiLocalTrack;
1115 1172
  */
1116 1173
 JitsiLocalTrack.prototype._setMute = function (mute) {
1117 1174
     if(!this.rtc) {
1118
-        console.error("Mute is not supported for streams not attached to conference!");
1175
+        this.startMuted = mute;
1119 1176
         return;
1120 1177
     }
1121 1178
     var isAudio = this.type === JitsiTrack.AUDIO;
1122 1179
     this.dontFireRemoveEvent = false;
1123 1180
 
1124 1181
     if ((window.location.protocol != "https:") ||
1125
-        (isAudio) || this.videoType === "screen" ||
1182
+        (isAudio) || this.videoType === "desktop" ||
1126 1183
         // FIXME FF does not support 'removeStream' method used to mute
1127 1184
         RTCBrowserType.isFirefox()) {
1128 1185
 
@@ -1134,7 +1191,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
1134 1191
             this.rtc.room.setAudioMute(mute);
1135 1192
         else
1136 1193
             this.rtc.room.setVideoMute(mute);
1137
-        this.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
1194
+        this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
1138 1195
     } else {
1139 1196
         if (mute) {
1140 1197
             this.dontFireRemoveEvent = true;
@@ -1145,7 +1202,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
1145 1202
             else
1146 1203
                 this.rtc.room.setVideoMute(mute);
1147 1204
             this.stream = null;
1148
-            this.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
1205
+            this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
1149 1206
             //FIXME: Maybe here we should set the SRC for the containers to something
1150 1207
         } else {
1151 1208
             var self = this;
@@ -1177,7 +1234,8 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
1177 1234
                                 self.rtc.room.setAudioMute(mute);
1178 1235
                             else
1179 1236
                                 self.rtc.room.setVideoMute(mute);
1180
-                            self.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, self);
1237
+                            self.eventEmitter.emit(
1238
+                                JitsiTrackEvents.TRACK_MUTE_CHANGED);
1181 1239
                         });
1182 1240
                 });
1183 1241
         }
@@ -1193,7 +1251,7 @@ JitsiLocalTrack.prototype.stop = function () {
1193 1251
         return;
1194 1252
     if(this.rtc)
1195 1253
         this.rtc.room.removeStream(this.stream);
1196
-    this.rtc.stopMediaStream(this.stream);
1254
+    RTC.stopMediaStream(this.stream);
1197 1255
     this.detach();
1198 1256
 }
1199 1257
 
@@ -1230,11 +1288,18 @@ JitsiLocalTrack.prototype._setRTC = function (rtc) {
1230 1288
     this.rtc = rtc;
1231 1289
 };
1232 1290
 
1291
+/**
1292
+ * Return true;
1293
+ */
1294
+JitsiLocalTrack.prototype.isLocal = function () {
1295
+    return true;
1296
+}
1297
+
1233 1298
 module.exports = JitsiLocalTrack;
1234 1299
 
1235
-},{"../../service/RTC/StreamEventTypes":84,"./JitsiTrack":14,"./RTCBrowserType":16,"./RTCUtils":17}],13:[function(require,module,exports){
1300
+},{"../../JitsiTrackEvents":10,"./JitsiTrack":14,"./RTCBrowserType":16,"./RTCUtils":17}],13:[function(require,module,exports){
1236 1301
 var JitsiTrack = require("./JitsiTrack");
1237
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
1302
+var JitsiTrackEvents = require("../../JitsiTrackEvents");
1238 1303
 
1239 1304
 /**
1240 1305
  * Represents a single media track (either audio or video).
@@ -1245,11 +1310,11 @@ var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
1245 1310
  * @param eventEmitter the event emitter
1246 1311
  * @constructor
1247 1312
  */
1248
-function JitsiRemoteTrack(RTC, data, sid, ssrc, eventEmitter) {
1313
+function JitsiRemoteTrack(RTC, data, sid, ssrc) {
1249 1314
     JitsiTrack.call(this, RTC, data.stream,
1250 1315
         function () {
1251
-            eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, self);
1252
-        });
1316
+            this.eventEmitter.emit(JitsiTrackEvents.TRACK_STOPPED);
1317
+        }.bind(this));
1253 1318
     this.rtc = RTC;
1254 1319
     this.sid = sid;
1255 1320
     this.stream = data.stream;
@@ -1259,10 +1324,8 @@ function JitsiRemoteTrack(RTC, data, sid, ssrc, eventEmitter) {
1259 1324
     this.muted = false;
1260 1325
     if((this.type === JitsiTrack.AUDIO && data.audiomuted)
1261 1326
       || (this.type === JitsiTrack.VIDEO && data.videomuted)) {
1262
-        this.muted = true
1327
+        this.muted = true;
1263 1328
     }
1264
-    this.eventEmitter = eventEmitter;
1265
-    var self = this;
1266 1329
 }
1267 1330
 
1268 1331
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
@@ -1275,7 +1338,7 @@ JitsiRemoteTrack.prototype.constructor = JitsiRemoteTrack;
1275 1338
 JitsiRemoteTrack.prototype.setMute = function (value) {
1276 1339
     this.stream.muted = value;
1277 1340
     this.muted = value;
1278
-    this.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
1341
+    this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
1279 1342
 };
1280 1343
 
1281 1344
 /**
@@ -1294,14 +1357,23 @@ JitsiRemoteTrack.prototype.getParitcipantId = function() {
1294 1357
     return Strophe.getResourceFromJid(this.peerjid);
1295 1358
 };
1296 1359
 
1360
+/**
1361
+ * Return false;
1362
+ */
1363
+JitsiRemoteTrack.prototype.isLocal = function () {
1364
+    return false;
1365
+}
1366
+
1297 1367
 delete JitsiRemoteTrack.prototype.stop;
1298 1368
 
1299 1369
 delete JitsiRemoteTrack.prototype.start;
1300 1370
 
1301 1371
 module.exports = JitsiRemoteTrack;
1302 1372
 
1303
-},{"../../service/RTC/StreamEventTypes":84,"./JitsiTrack":14}],14:[function(require,module,exports){
1373
+},{"../../JitsiTrackEvents":10,"./JitsiTrack":14}],14:[function(require,module,exports){
1304 1374
 var RTCBrowserType = require("./RTCBrowserType");
1375
+var JitsiTrackEvents = require("../../JitsiTrackEvents");
1376
+var EventEmitter = require("events");
1305 1377
 
1306 1378
 /**
1307 1379
  * This implements 'onended' callback normally fired by WebRTC after the stream
@@ -1357,6 +1429,8 @@ function JitsiTrack(rtc, stream, streamInactiveHandler)
1357 1429
     this.containers = [];
1358 1430
     this.rtc = rtc;
1359 1431
     this.stream = stream;
1432
+    this.eventEmitter = new EventEmitter();
1433
+    this.audioLevel = -1;
1360 1434
     this.type = (this.stream.getVideoTracks().length > 0)?
1361 1435
         JitsiTrack.VIDEO : JitsiTrack.AUDIO;
1362 1436
     if(this.type == "audio") {
@@ -1487,10 +1561,47 @@ JitsiTrack.prototype.isActive = function () {
1487 1561
         return true;
1488 1562
 };
1489 1563
 
1564
+/**
1565
+ * Attaches a handler for events(For example - "audio level changed".).
1566
+ * All possible event are defined in JitsiTrackEvents.
1567
+ * @param eventId the event ID.
1568
+ * @param handler handler for the event.
1569
+ */
1570
+JitsiTrack.prototype.on = function (eventId, handler) {
1571
+    if(this.eventEmitter)
1572
+        this.eventEmitter.on(eventId, handler);
1573
+}
1574
+
1575
+/**
1576
+ * Removes event listener
1577
+ * @param eventId the event ID.
1578
+ * @param [handler] optional, the specific handler to unbind
1579
+ */
1580
+JitsiTrack.prototype.off = function (eventId, handler) {
1581
+    if(this.eventEmitter)
1582
+        this.eventEmitter.removeListener(eventId, handler);
1583
+}
1584
+
1585
+// Common aliases for event emitter
1586
+JitsiTrack.prototype.addEventListener = JitsiTrack.prototype.on;
1587
+JitsiTrack.prototype.removeEventListener = JitsiTrack.prototype.off;
1588
+
1589
+
1590
+/**
1591
+ * Sets the audio level for the stream
1592
+ * @param audioLevel the new audio level
1593
+ */
1594
+JitsiTrack.prototype.setAudioLevel = function (audioLevel) {
1595
+    if(this.audioLevel !== audioLevel) {
1596
+        this.eventEmitter.emit(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
1597
+            audioLevel);
1598
+        this.audioLevel = audioLevel;
1599
+    }
1600
+ }
1490 1601
 
1491 1602
 module.exports = JitsiTrack;
1492 1603
 
1493
-},{"./RTCBrowserType":16,"./RTCUtils":17}],15:[function(require,module,exports){
1604
+},{"../../JitsiTrackEvents":10,"./RTCBrowserType":16,"./RTCUtils":17,"events":42}],15:[function(require,module,exports){
1494 1605
 /* global APP */
1495 1606
 var EventEmitter = require("events");
1496 1607
 var RTCBrowserType = require("./RTCBrowserType");
@@ -1502,7 +1613,6 @@ var JitsiRemoteTrack = require("./JitsiRemoteTrack.js");
1502 1613
 var DesktopSharingEventTypes
1503 1614
     = require("../../service/desktopsharing/DesktopSharingEventTypes");
1504 1615
 var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
1505
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
1506 1616
 var RTCEvents = require("../../service/RTC/RTCEvents.js");
1507 1617
 
1508 1618
 function createLocalTracks(streams) {
@@ -1513,10 +1623,6 @@ function createLocalTracks(streams) {
1513 1623
         newStreams.push(localStream);
1514 1624
         if (streams[i].isMuted === true)
1515 1625
             localStream.setMute(true);
1516
-        //FIXME:
1517
-        // var eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CREATED;
1518
-        //
1519
-        // eventEmitter.emit(eventType, localStream);
1520 1626
     }
1521 1627
     return newStreams;
1522 1628
 }
@@ -1524,6 +1630,8 @@ function createLocalTracks(streams) {
1524 1630
 function RTC(room, options) {
1525 1631
     this.room = room;
1526 1632
     this.localStreams = [];
1633
+    //FIXME: we should start removing those streams.
1634
+    //FIXME: We should support multiple streams per jid.
1527 1635
     this.remoteStreams = {};
1528 1636
     this.localAudio = null;
1529 1637
     this.localVideo = null;
@@ -1531,12 +1639,14 @@ function RTC(room, options) {
1531 1639
     var self = this;
1532 1640
     this.options = options || {};
1533 1641
     room.addPresenceListener("videomuted", function (values, from) {
1534
-        if(self.remoteStreams[from])
1642
+        if(self.remoteStreams[from]) {
1535 1643
             self.remoteStreams[from][JitsiTrack.VIDEO].setMute(values.value == "true");
1644
+        }
1536 1645
     });
1537 1646
     room.addPresenceListener("audiomuted", function (values, from) {
1538
-        if(self.remoteStreams[from])
1647
+        if(self.remoteStreams[from]) {
1539 1648
             self.remoteStreams[from][JitsiTrack.AUDIO].setMute(values.value == "true");
1649
+        }
1540 1650
     });
1541 1651
 }
1542 1652
 
@@ -1597,7 +1707,8 @@ RTC.isRTCReady = function () {
1597 1707
 }
1598 1708
 
1599 1709
 RTC.init = function (options) {
1600
-    return RTCUtils.init(options || {});
1710
+    this.options = options || {};
1711
+    return RTCUtils.init(this.options);
1601 1712
 }
1602 1713
 
1603 1714
 RTC.getDeviceAvailability = function () {
@@ -1625,8 +1736,7 @@ RTC.prototype.removeLocalStream = function (stream) {
1625 1736
 };
1626 1737
 
1627 1738
 RTC.prototype.createRemoteStream = function (data, sid, thessrc) {
1628
-    var remoteStream = new JitsiRemoteTrack(this, data, sid, thessrc,
1629
-        this.eventEmitter);
1739
+    var remoteStream = new JitsiRemoteTrack(this, data, sid, thessrc);
1630 1740
     if(!data.peerjid)
1631 1741
         return;
1632 1742
     var jid = data.peerjid;
@@ -1634,7 +1744,6 @@ RTC.prototype.createRemoteStream = function (data, sid, thessrc) {
1634 1744
         this.remoteStreams[jid] = {};
1635 1745
     }
1636 1746
     this.remoteStreams[jid][remoteStream.type]= remoteStream;
1637
-    this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
1638 1747
     return remoteStream;
1639 1748
 };
1640 1749
 
@@ -1686,24 +1795,6 @@ RTC.prototype.getVideoElementName = function () {
1686 1795
 RTC.prototype.dispose = function() {
1687 1796
 };
1688 1797
 
1689
-RTC.prototype.muteRemoteVideoStream = function (jid, value) {
1690
-    var stream;
1691
-
1692
-    if(this.remoteStreams[jid] &&
1693
-        this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
1694
-        stream = this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
1695
-    }
1696
-
1697
-    if(!stream)
1698
-        return true;
1699
-
1700
-    if (value != stream.muted) {
1701
-        stream.setMute(value);
1702
-        return true;
1703
-    }
1704
-    return false;
1705
-};
1706
-
1707 1798
 RTC.prototype.switchVideoStreams = function (newStream) {
1708 1799
     this.localVideo.stream = newStream;
1709 1800
 
@@ -1715,42 +1806,13 @@ RTC.prototype.switchVideoStreams = function (newStream) {
1715 1806
     this.localStreams.push(this.localVideo);
1716 1807
 };
1717 1808
 
1718
-RTC.prototype.isVideoMuted = function (jid) {
1719
-    if (jid === APP.xmpp.myJid()) {
1720
-        var localVideo = APP.RTC.localVideo;
1721
-        return (!localVideo || localVideo.isMuted());
1722
-    } else {
1723
-        if (!this.remoteStreams[jid] ||
1724
-            !this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
1725
-            return null;
1726
-        }
1727
-        return this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
1728
-    }
1729
-};
1730
-
1731
-RTC.prototype.setVideoMute = function (mute, callback, options) {
1732
-    if (!this.localVideo)
1733
-        return;
1734
-
1735
-    if (mute == this.localVideo.isMuted())
1736
-    {
1737
-        APP.xmpp.sendVideoInfoPresence(mute);
1738
-        if (callback)
1739
-            callback(mute);
1740
-    }
1741
-    else
1742
-    {
1743
-        this.localVideo.setMute(mute);
1744
-        this.room.setVideoMute(
1745
-            mute,
1746
-            callback,
1747
-            options);
1748
-    }
1749
-};
1750
-
1809
+RTC.prototype.setAudioLevel = function (jid, audioLevel) {
1810
+    if(this.remoteStreams[jid] && this.remoteStreams[jid][JitsiTrack.AUDIO])
1811
+        this.remoteStreams[jid][JitsiTrack.AUDIO].setAudioLevel(audioLevel);
1812
+}
1751 1813
 module.exports = RTC;
1752 1814
 
1753
-},{"../../service/RTC/MediaStreamTypes":81,"../../service/RTC/RTCEvents.js":82,"../../service/RTC/StreamEventTypes.js":84,"../../service/desktopsharing/DesktopSharingEventTypes":86,"./DataChannels":11,"./JitsiLocalTrack.js":12,"./JitsiRemoteTrack.js":13,"./JitsiTrack":14,"./RTCBrowserType":16,"./RTCUtils.js":17,"events":42}],16:[function(require,module,exports){
1815
+},{"../../service/RTC/MediaStreamTypes":81,"../../service/RTC/RTCEvents.js":82,"../../service/desktopsharing/DesktopSharingEventTypes":85,"./DataChannels":11,"./JitsiLocalTrack.js":12,"./JitsiRemoteTrack.js":13,"./JitsiTrack":14,"./RTCBrowserType":16,"./RTCUtils.js":17,"events":42}],16:[function(require,module,exports){
1754 1816
 
1755 1817
 var currentBrowser;
1756 1818
 
@@ -3094,7 +3156,7 @@ function initFirefoxExtensionDetection(options) {
3094 3156
 module.exports = ScreenObtainer;
3095 3157
 
3096 3158
 }).call(this,"/modules/RTC/ScreenObtainer.js")
3097
-},{"../../service/desktopsharing/DesktopSharingEventTypes":86,"./RTCBrowserType":16,"./adapter.screenshare":19,"jitsi-meet-logger":46}],19:[function(require,module,exports){
3159
+},{"../../service/desktopsharing/DesktopSharingEventTypes":85,"./RTCBrowserType":16,"./adapter.screenshare":19,"jitsi-meet-logger":46}],19:[function(require,module,exports){
3098 3160
 (function (__filename){
3099 3161
 /*! adapterjs - v0.12.0 - 2015-09-04 */
3100 3162
 var console = require("jitsi-meet-logger").getLogger(__filename);
@@ -4360,9 +4422,6 @@ module.exports = Settings;
4360 4422
  */
4361 4423
 
4362 4424
 var RTCBrowserType = require('../RTC/RTCBrowserType');
4363
-var StatisticsEvents = require('../../service/statistics/Events');
4364
-
4365
-var LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
4366 4425
 
4367 4426
 /**
4368 4427
  * Size of the webaudio analyzer buffer.
@@ -4423,16 +4482,16 @@ function animateLevel(newLevel, lastLevel) {
4423 4482
  *
4424 4483
  * @param stream the local stream
4425 4484
  * @param interval stats refresh interval given in ms.
4485
+ * @param callback function that receives the audio levels.
4426 4486
  * @constructor
4427 4487
  */
4428
-function LocalStatsCollector(stream, interval, statisticsService, eventEmitter) {
4488
+function LocalStatsCollector(stream, interval, callback) {
4429 4489
     window.AudioContext = window.AudioContext || window.webkitAudioContext;
4430 4490
     this.stream = stream;
4431 4491
     this.intervalId = null;
4432 4492
     this.intervalMilis = interval;
4433
-    this.eventEmitter = eventEmitter;
4434 4493
     this.audioLevel = 0;
4435
-    this.statisticsService = statisticsService;
4494
+    this.callback = callback;
4436 4495
 }
4437 4496
 
4438 4497
 /**
@@ -4462,10 +4521,7 @@ LocalStatsCollector.prototype.start = function () {
4462 4521
             var audioLevel = timeDomainDataToAudioLevel(array);
4463 4522
             if (audioLevel != self.audioLevel) {
4464 4523
                 self.audioLevel = animateLevel(audioLevel, self.audioLevel);
4465
-                self.eventEmitter.emit(
4466
-                    StatisticsEvents.AUDIO_LEVEL,
4467
-                    self.statisticsService.LOCAL_JID,
4468
-                    self.audioLevel);
4524
+                self.callback(self.audioLevel);
4469 4525
             }
4470 4526
         },
4471 4527
         this.intervalMilis
@@ -4483,7 +4539,8 @@ LocalStatsCollector.prototype.stop = function () {
4483 4539
 };
4484 4540
 
4485 4541
 module.exports = LocalStatsCollector;
4486
-},{"../../service/statistics/Events":87,"../../service/statistics/constants":88,"../RTC/RTCBrowserType":16}],22:[function(require,module,exports){
4542
+
4543
+},{"../RTC/RTCBrowserType":16}],22:[function(require,module,exports){
4487 4544
 (function (__filename){
4488 4545
 /* global require, ssrc2jid */
4489 4546
 /* jshint -W117 */
@@ -5210,7 +5267,7 @@ StatsCollector.prototype.processAudioLevelReport = function () {
5210 5267
 };
5211 5268
 
5212 5269
 }).call(this,"/modules/statistics/RTPStatsCollector.js")
5213
-},{"../../service/statistics/Events":87,"../RTC/RTCBrowserType":16,"jitsi-meet-logger":46}],23:[function(require,module,exports){
5270
+},{"../../service/statistics/Events":86,"../RTC/RTCBrowserType":16,"jitsi-meet-logger":46}],23:[function(require,module,exports){
5214 5271
 /* global require, APP */
5215 5272
 var LocalStats = require("./LocalStatsCollector.js");
5216 5273
 var RTPStats = require("./RTPStatsCollector.js");
@@ -5231,8 +5288,9 @@ var StatisticsEvents = require("../../service/statistics/Events");
5231 5288
 //    }
5232 5289
 //}
5233 5290
 
5291
+var eventEmitter = new EventEmitter();
5292
+
5234 5293
 function Statistics() {
5235
-    this.localStats = null;
5236 5294
     this.rtpStats = null;
5237 5295
     this.eventEmitter = new EventEmitter();
5238 5296
 }
@@ -5246,14 +5304,13 @@ Statistics.prototype.startRemoteStats = function (peerconnection) {
5246 5304
     this.rtpStats.start();
5247 5305
 }
5248 5306
 
5249
-Statistics.prototype.startLocalStats = function (stream) {
5250
-    if(stream.getType() !== "audio")
5251
-        return;
5252
-    this.localStats = new LocalStats(stream.getOriginalStream(), 200, this,
5253
-        this.eventEmitter);
5254
-    this.localStats.start();
5255
-}
5307
+Statistics.localStats = [];
5256 5308
 
5309
+Statistics.startLocalStats = function (stream, callback) {
5310
+    var localStats = new LocalStats(stream, 200, callback);
5311
+    this.localStats.push(localStats);
5312
+    localStats.start();
5313
+}
5257 5314
 
5258 5315
 Statistics.prototype.addAudioLevelListener = function(listener)
5259 5316
 {
@@ -5266,20 +5323,29 @@ Statistics.prototype.removeAudioLevelListener = function(listener)
5266 5323
 }
5267 5324
 
5268 5325
 Statistics.prototype.dispose = function () {
5269
-    this.stopLocal();
5326
+    Statistics.stopAllLocalStats();
5270 5327
     this.stopRemote();
5271 5328
     if(this.eventEmitter)
5272
-    {
5273 5329
         this.eventEmitter.removeAllListeners();
5274
-    }
5330
+
5331
+    if(eventEmitter)
5332
+        eventEmitter.removeAllListeners();
5275 5333
 }
5276 5334
 
5277 5335
 
5278
-Statistics.prototype.stopLocal = function () {
5279
-    if (this.localStats) {
5280
-        this.localStats.stop();
5281
-        this.localStats = null;
5282
-    }
5336
+Statistics.stopAllLocalStats = function () {
5337
+    for(var i = 0; i < this.localStats.length; i++)
5338
+        this.localStats[i].stop();
5339
+    this.localStats = [];
5340
+}
5341
+
5342
+Statistics.stopLocalStats = function (stream) {
5343
+    for(var i = 0; i < Statistics.localStats.length; i++)
5344
+        if(Statistics.localStats[i].stream === stream){
5345
+            var localStats = Statistics.localStats.splice(i, 1);
5346
+            localStats.stop();
5347
+            break;
5348
+        }
5283 5349
 }
5284 5350
 
5285 5351
 Statistics.prototype.stopRemote = function () {
@@ -5358,7 +5424,8 @@ Statistics.LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
5358 5424
 
5359 5425
 
5360 5426
 module.exports = Statistics;
5361
-},{"../../service/statistics/Events":87,"../../service/statistics/constants":88,"./LocalStatsCollector.js":21,"./RTPStatsCollector.js":22,"events":42}],24:[function(require,module,exports){
5427
+
5428
+},{"../../service/statistics/Events":86,"../../service/statistics/constants":87,"./LocalStatsCollector.js":21,"./RTPStatsCollector.js":22,"events":42}],24:[function(require,module,exports){
5362 5429
 /**
5363 5430
 /**
5364 5431
  * @const
@@ -5952,10 +6019,10 @@ ChatRoom.prototype.setJingleSession = function(session){
5952 6019
 };
5953 6020
 
5954 6021
 
5955
-ChatRoom.prototype.removeStream = function (stream) {
6022
+ChatRoom.prototype.removeStream = function (stream, callback) {
5956 6023
     if(!this.session)
5957 6024
         return;
5958
-    this.session.peerconnection.removeStream(stream)
6025
+    this.session.removeStream(stream, callback);
5959 6026
 }
5960 6027
 
5961 6028
 ChatRoom.prototype.switchStreams = function (stream, oldStream, callback, isAudio) {
@@ -6079,7 +6146,7 @@ ChatRoom.prototype.getJidBySSRC = function (ssrc) {
6079 6146
 module.exports = ChatRoom;
6080 6147
 
6081 6148
 }).call(this,"/modules/xmpp/ChatRoom.js")
6082
-},{"../../service/xmpp/XMPPEvents":89,"./moderator":33,"events":42,"jitsi-meet-logger":46}],26:[function(require,module,exports){
6149
+},{"../../service/xmpp/XMPPEvents":88,"./moderator":33,"events":42,"jitsi-meet-logger":46}],26:[function(require,module,exports){
6083 6150
 (function (__filename){
6084 6151
 /*
6085 6152
  * JingleSession provides an API to manage a single Jingle session. We will
@@ -7454,6 +7521,43 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
7454 7521
     });
7455 7522
 }
7456 7523
 
7524
+/**
7525
+ * Remove streams.
7526
+ * @param stream stream that will be removed.
7527
+ * @param success_callback callback executed after successful stream addition.
7528
+ */
7529
+JingleSessionPC.prototype.removeStream = function (stream, callback) {
7530
+
7531
+    var self = this;
7532
+
7533
+    // Remember SDP to figure out added/removed SSRCs
7534
+    var oldSdp = null;
7535
+    if(this.peerconnection) {
7536
+        if(this.peerconnection.localDescription) {
7537
+            oldSdp = new SDP(this.peerconnection.localDescription.sdp);
7538
+        }
7539
+        if(stream)
7540
+            this.peerconnection.removeStream(stream);
7541
+    }
7542
+
7543
+    // Conference is not active
7544
+    if(!oldSdp || !this.peerconnection) {
7545
+        callback();
7546
+        return;
7547
+    }
7548
+
7549
+    this.addingStreams = true;
7550
+    this.modifySourcesQueue.push(function() {
7551
+        logger.log('modify sources done');
7552
+
7553
+        callback();
7554
+
7555
+        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
7556
+        logger.log("SDPs", oldSdp, newSdp);
7557
+        self.notifyMySSRCUpdate(oldSdp, newSdp);
7558
+    });
7559
+}
7560
+
7457 7561
 /**
7458 7562
  * Figures out added/removed ssrcs and send update IQs.
7459 7563
  * @param old_sdp SDP object for old description.
@@ -7805,7 +7909,7 @@ JingleSessionPC.prototype.remoteStreamAdded = function (data, times) {
7805 7909
 module.exports = JingleSessionPC;
7806 7910
 
7807 7911
 }).call(this,"/modules/xmpp/JingleSessionPC.js")
7808
-},{"../../service/xmpp/XMPPEvents":89,"../RTC/RTC":15,"../RTC/RTCBrowserType":16,"./JingleSession":26,"./LocalSSRCReplacement":28,"./SDP":29,"./SDPDiffer":30,"./SDPUtil":31,"./TraceablePeerConnection":32,"async":41,"jitsi-meet-logger":46,"sdp-transform":78}],28:[function(require,module,exports){
7912
+},{"../../service/xmpp/XMPPEvents":88,"../RTC/RTC":15,"../RTC/RTCBrowserType":16,"./JingleSession":26,"./LocalSSRCReplacement":28,"./SDP":29,"./SDPDiffer":30,"./SDPUtil":31,"./TraceablePeerConnection":32,"async":41,"jitsi-meet-logger":46,"sdp-transform":78}],28:[function(require,module,exports){
7809 7913
 (function (__filename){
7810 7914
 /* global $ */
7811 7915
 var logger = require("jitsi-meet-logger").getLogger(__filename);
@@ -9742,7 +9846,7 @@ TraceablePeerConnection.prototype.getStats = function(callback, errback) {
9742 9846
 module.exports = TraceablePeerConnection;
9743 9847
 
9744 9848
 }).call(this,"/modules/xmpp/TraceablePeerConnection.js")
9745
-},{"../../service/xmpp/XMPPEvents":89,"../RTC/RTC":15,"../RTC/RTCBrowserType.js":16,"./LocalSSRCReplacement":28,"jitsi-meet-logger":46,"sdp-interop":64,"sdp-simulcast":71,"sdp-transform":78}],33:[function(require,module,exports){
9849
+},{"../../service/xmpp/XMPPEvents":88,"../RTC/RTC":15,"../RTC/RTCBrowserType.js":16,"./LocalSSRCReplacement":28,"jitsi-meet-logger":46,"sdp-interop":64,"sdp-simulcast":71,"sdp-transform":78}],33:[function(require,module,exports){
9746 9850
 (function (__filename){
9747 9851
 /* global $, $iq, APP, config, messageHandler,
9748 9852
  roomName, sessionTerminated, Strophe, Util */
@@ -10179,7 +10283,7 @@ module.exports = Moderator;
10179 10283
 
10180 10284
 
10181 10285
 }).call(this,"/modules/xmpp/moderator.js")
10182
-},{"../../service/authentication/AuthenticationEvents":85,"../../service/xmpp/XMPPEvents":89,"../settings/Settings":20,"jitsi-meet-logger":46}],34:[function(require,module,exports){
10286
+},{"../../service/authentication/AuthenticationEvents":84,"../../service/xmpp/XMPPEvents":88,"../settings/Settings":20,"jitsi-meet-logger":46}],34:[function(require,module,exports){
10183 10287
 (function (__filename){
10184 10288
 /* jshint -W117 */
10185 10289
 /* a simple MUC connection plugin
@@ -10573,7 +10677,7 @@ module.exports = function(XMPP, eventEmitter) {
10573 10677
 
10574 10678
 
10575 10679
 }).call(this,"/modules/xmpp/strophe.jingle.js")
10576
-},{"../../service/xmpp/XMPPEvents":89,"../RTC/RTCBrowserType":16,"./JingleSessionPC":27,"jitsi-meet-logger":46}],36:[function(require,module,exports){
10680
+},{"../../service/xmpp/XMPPEvents":88,"../RTC/RTCBrowserType":16,"./JingleSessionPC":27,"jitsi-meet-logger":46}],36:[function(require,module,exports){
10577 10681
 /* global Strophe */
10578 10682
 module.exports = function () {
10579 10683
 
@@ -10721,7 +10825,7 @@ module.exports = function (XMPP, eventEmitter) {
10721 10825
 };
10722 10826
 
10723 10827
 }).call(this,"/modules/xmpp/strophe.ping.js")
10724
-},{"../../service/xmpp/XMPPEvents":89,"jitsi-meet-logger":46}],38:[function(require,module,exports){
10828
+},{"../../service/xmpp/XMPPEvents":88,"jitsi-meet-logger":46}],38:[function(require,module,exports){
10725 10829
 (function (__filename){
10726 10830
 /* jshint -W117 */
10727 10831
 var logger = require("jitsi-meet-logger").getLogger(__filename);
@@ -10879,7 +10983,6 @@ module.exports = function () {
10879 10983
 var logger = require("jitsi-meet-logger").getLogger(__filename);
10880 10984
 var EventEmitter = require("events");
10881 10985
 var Pako = require("pako");
10882
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
10883 10986
 var RTCEvents = require("../../service/RTC/RTCEvents");
10884 10987
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
10885 10988
 var JitsiConnectionErrors = require("../../JitsiConnectionErrors");
@@ -11000,7 +11103,7 @@ XMPP.prototype._connect = function (jid, password) {
11000 11103
                         logger.warn("Ping NOT supported by " + pingJid);
11001 11104
                 }
11002 11105
             );
11003
-            
11106
+
11004 11107
             if (password)
11005 11108
                 authenticatedUser = true;
11006 11109
             if (self.connection && self.connection.connected &&
@@ -11180,7 +11283,7 @@ XMPP.prototype.disconnect = function () {
11180 11283
 module.exports = XMPP;
11181 11284
 
11182 11285
 }).call(this,"/modules/xmpp/xmpp.js")
11183
-},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":82,"../../service/RTC/StreamEventTypes":84,"../../service/xmpp/XMPPEvents":89,"../RTC/RTC":15,"./strophe.emuc":34,"./strophe.jingle":35,"./strophe.logger":36,"./strophe.ping":37,"./strophe.rayo":38,"./strophe.util":39,"events":42,"jitsi-meet-logger":46,"pako":47}],41:[function(require,module,exports){
11286
+},{"../../JitsiConnectionErrors":5,"../../JitsiConnectionEvents":6,"../../service/RTC/RTCEvents":82,"../../service/xmpp/XMPPEvents":88,"../RTC/RTC":15,"./strophe.emuc":34,"./strophe.jingle":35,"./strophe.logger":36,"./strophe.ping":37,"./strophe.rayo":38,"./strophe.util":39,"events":42,"jitsi-meet-logger":46,"pako":47}],41:[function(require,module,exports){
11184 11287
 (function (process){
11185 11288
 /*!
11186 11289
  * async
@@ -22285,21 +22388,6 @@ var Resolutions = {
22285 22388
 };
22286 22389
 module.exports = Resolutions;
22287 22390
 },{}],84:[function(require,module,exports){
22288
-var StreamEventTypes = {
22289
-    EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
22290
-
22291
-    EVENT_TYPE_LOCAL_CHANGED: "stream.local_changed",
22292
-
22293
-    EVENT_TYPE_LOCAL_ENDED: "stream.local_ended",
22294
-
22295
-    EVENT_TYPE_REMOTE_CREATED: "stream.remote_created",
22296
-
22297
-    EVENT_TYPE_REMOTE_ENDED: "stream.remote_ended",
22298
-    TRACK_MUTE_CHANGED: "rtc.track_mute_changed"
22299
-};
22300
-
22301
-module.exports = StreamEventTypes;
22302
-},{}],85:[function(require,module,exports){
22303 22391
 var AuthenticationEvents = {
22304 22392
     /**
22305 22393
      * Event callback arguments:
@@ -22313,7 +22401,7 @@ var AuthenticationEvents = {
22313 22401
 };
22314 22402
 module.exports = AuthenticationEvents;
22315 22403
 
22316
-},{}],86:[function(require,module,exports){
22404
+},{}],85:[function(require,module,exports){
22317 22405
 var DesktopSharingEventTypes = {
22318 22406
     INIT: "ds.init",
22319 22407
 
@@ -22329,7 +22417,7 @@ var DesktopSharingEventTypes = {
22329 22417
 
22330 22418
 module.exports = DesktopSharingEventTypes;
22331 22419
 
22332
-},{}],87:[function(require,module,exports){
22420
+},{}],86:[function(require,module,exports){
22333 22421
 module.exports = {
22334 22422
     /**
22335 22423
      * An event carrying connection statistics.
@@ -22345,12 +22433,12 @@ module.exports = {
22345 22433
     STOP: "statistics.stop"
22346 22434
 };
22347 22435
 
22348
-},{}],88:[function(require,module,exports){
22436
+},{}],87:[function(require,module,exports){
22349 22437
 var Constants = {
22350 22438
     LOCAL_JID: 'local'
22351 22439
 };
22352 22440
 module.exports = Constants;
22353
-},{}],89:[function(require,module,exports){
22441
+},{}],88:[function(require,module,exports){
22354 22442
 var XMPPEvents = {
22355 22443
     // Designates an event indicating that the connection to the XMPP server
22356 22444
     // failed.

+ 21
- 12
modules/RTC/JitsiLocalTrack.js View File

@@ -1,6 +1,6 @@
1 1
 var JitsiTrack = require("./JitsiTrack");
2
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
3 2
 var RTCBrowserType = require("./RTCBrowserType");
3
+var JitsiTrackEvents = require('../../JitsiTrackEvents');
4 4
 var RTC = require("./RTCUtils");
5 5
 
6 6
 /**
@@ -13,14 +13,15 @@ function JitsiLocalTrack(stream, videoType,
13 13
     this.videoType = videoType;
14 14
     this.dontFireRemoveEvent = false;
15 15
     this.resolution = resolution;
16
+    this.startMuted = false;
16 17
     var self = this;
17 18
     JitsiTrack.call(this, null, stream,
18 19
         function () {
19
-            if(!self.dontFireRemoveEvent && self.rtc)
20
-                self.rtc.eventEmitter.emit(
21
-                    StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, self);
22
-            self.dontFireRemoveEvent = false;
23
-        });
20
+            if(!this.dontFireRemoveEvent)
21
+                this.eventEmitter.emit(
22
+                    JitsiTrackEvents.TRACK_STOPPED);
23
+            this.dontFireRemoveEvent = false;
24
+        }.bind(this));
24 25
 
25 26
 }
26 27
 
@@ -33,14 +34,14 @@ JitsiLocalTrack.prototype.constructor = JitsiLocalTrack;
33 34
  */
34 35
 JitsiLocalTrack.prototype._setMute = function (mute) {
35 36
     if(!this.rtc) {
36
-        console.error("Mute is not supported for streams not attached to conference!");
37
+        this.startMuted = mute;
37 38
         return;
38 39
     }
39 40
     var isAudio = this.type === JitsiTrack.AUDIO;
40 41
     this.dontFireRemoveEvent = false;
41 42
 
42 43
     if ((window.location.protocol != "https:") ||
43
-        (isAudio) || this.videoType === "screen" ||
44
+        (isAudio) || this.videoType === "desktop" ||
44 45
         // FIXME FF does not support 'removeStream' method used to mute
45 46
         RTCBrowserType.isFirefox()) {
46 47
 
@@ -52,7 +53,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
52 53
             this.rtc.room.setAudioMute(mute);
53 54
         else
54 55
             this.rtc.room.setVideoMute(mute);
55
-        this.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
56
+        this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
56 57
     } else {
57 58
         if (mute) {
58 59
             this.dontFireRemoveEvent = true;
@@ -63,7 +64,7 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
63 64
             else
64 65
                 this.rtc.room.setVideoMute(mute);
65 66
             this.stream = null;
66
-            this.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
67
+            this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
67 68
             //FIXME: Maybe here we should set the SRC for the containers to something
68 69
         } else {
69 70
             var self = this;
@@ -95,7 +96,8 @@ JitsiLocalTrack.prototype._setMute = function (mute) {
95 96
                                 self.rtc.room.setAudioMute(mute);
96 97
                             else
97 98
                                 self.rtc.room.setVideoMute(mute);
98
-                            self.rtc.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, self);
99
+                            self.eventEmitter.emit(
100
+                                JitsiTrackEvents.TRACK_MUTE_CHANGED);
99 101
                         });
100 102
                 });
101 103
         }
@@ -111,7 +113,7 @@ JitsiLocalTrack.prototype.stop = function () {
111 113
         return;
112 114
     if(this.rtc)
113 115
         this.rtc.room.removeStream(this.stream);
114
-    this.rtc.stopMediaStream(this.stream);
116
+    RTC.stopMediaStream(this.stream);
115 117
     this.detach();
116 118
 }
117 119
 
@@ -148,4 +150,11 @@ JitsiLocalTrack.prototype._setRTC = function (rtc) {
148 150
     this.rtc = rtc;
149 151
 };
150 152
 
153
+/**
154
+ * Return true;
155
+ */
156
+JitsiLocalTrack.prototype.isLocal = function () {
157
+    return true;
158
+}
159
+
151 160
 module.exports = JitsiLocalTrack;

+ 13
- 8
modules/RTC/JitsiRemoteTrack.js View File

@@ -1,5 +1,5 @@
1 1
 var JitsiTrack = require("./JitsiTrack");
2
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
2
+var JitsiTrackEvents = require("../../JitsiTrackEvents");
3 3
 
4 4
 /**
5 5
  * Represents a single media track (either audio or video).
@@ -10,11 +10,11 @@ var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
10 10
  * @param eventEmitter the event emitter
11 11
  * @constructor
12 12
  */
13
-function JitsiRemoteTrack(RTC, data, sid, ssrc, eventEmitter) {
13
+function JitsiRemoteTrack(RTC, data, sid, ssrc) {
14 14
     JitsiTrack.call(this, RTC, data.stream,
15 15
         function () {
16
-            eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_ENDED, self);
17
-        });
16
+            this.eventEmitter.emit(JitsiTrackEvents.TRACK_STOPPED);
17
+        }.bind(this));
18 18
     this.rtc = RTC;
19 19
     this.sid = sid;
20 20
     this.stream = data.stream;
@@ -24,10 +24,8 @@ function JitsiRemoteTrack(RTC, data, sid, ssrc, eventEmitter) {
24 24
     this.muted = false;
25 25
     if((this.type === JitsiTrack.AUDIO && data.audiomuted)
26 26
       || (this.type === JitsiTrack.VIDEO && data.videomuted)) {
27
-        this.muted = true
27
+        this.muted = true;
28 28
     }
29
-    this.eventEmitter = eventEmitter;
30
-    var self = this;
31 29
 }
32 30
 
33 31
 JitsiRemoteTrack.prototype = Object.create(JitsiTrack.prototype);
@@ -40,7 +38,7 @@ JitsiRemoteTrack.prototype.constructor = JitsiRemoteTrack;
40 38
 JitsiRemoteTrack.prototype.setMute = function (value) {
41 39
     this.stream.muted = value;
42 40
     this.muted = value;
43
-    this.eventEmitter.emit(StreamEventTypes.TRACK_MUTE_CHANGED, this);
41
+    this.eventEmitter.emit(JitsiTrackEvents.TRACK_MUTE_CHANGED);
44 42
 };
45 43
 
46 44
 /**
@@ -59,6 +57,13 @@ JitsiRemoteTrack.prototype.getParitcipantId = function() {
59 57
     return Strophe.getResourceFromJid(this.peerjid);
60 58
 };
61 59
 
60
+/**
61
+ * Return false;
62
+ */
63
+JitsiRemoteTrack.prototype.isLocal = function () {
64
+    return false;
65
+}
66
+
62 67
 delete JitsiRemoteTrack.prototype.stop;
63 68
 
64 69
 delete JitsiRemoteTrack.prototype.start;

+ 41
- 0
modules/RTC/JitsiTrack.js View File

@@ -1,4 +1,6 @@
1 1
 var RTCBrowserType = require("./RTCBrowserType");
2
+var JitsiTrackEvents = require("../../JitsiTrackEvents");
3
+var EventEmitter = require("events");
2 4
 
3 5
 /**
4 6
  * This implements 'onended' callback normally fired by WebRTC after the stream
@@ -54,6 +56,8 @@ function JitsiTrack(rtc, stream, streamInactiveHandler)
54 56
     this.containers = [];
55 57
     this.rtc = rtc;
56 58
     this.stream = stream;
59
+    this.eventEmitter = new EventEmitter();
60
+    this.audioLevel = -1;
57 61
     this.type = (this.stream.getVideoTracks().length > 0)?
58 62
         JitsiTrack.VIDEO : JitsiTrack.AUDIO;
59 63
     if(this.type == "audio") {
@@ -184,5 +188,42 @@ JitsiTrack.prototype.isActive = function () {
184 188
         return true;
185 189
 };
186 190
 
191
+/**
192
+ * Attaches a handler for events(For example - "audio level changed".).
193
+ * All possible event are defined in JitsiTrackEvents.
194
+ * @param eventId the event ID.
195
+ * @param handler handler for the event.
196
+ */
197
+JitsiTrack.prototype.on = function (eventId, handler) {
198
+    if(this.eventEmitter)
199
+        this.eventEmitter.on(eventId, handler);
200
+}
201
+
202
+/**
203
+ * Removes event listener
204
+ * @param eventId the event ID.
205
+ * @param [handler] optional, the specific handler to unbind
206
+ */
207
+JitsiTrack.prototype.off = function (eventId, handler) {
208
+    if(this.eventEmitter)
209
+        this.eventEmitter.removeListener(eventId, handler);
210
+}
211
+
212
+// Common aliases for event emitter
213
+JitsiTrack.prototype.addEventListener = JitsiTrack.prototype.on;
214
+JitsiTrack.prototype.removeEventListener = JitsiTrack.prototype.off;
215
+
216
+
217
+/**
218
+ * Sets the audio level for the stream
219
+ * @param audioLevel the new audio level
220
+ */
221
+JitsiTrack.prototype.setAudioLevel = function (audioLevel) {
222
+    if(this.audioLevel !== audioLevel) {
223
+        this.eventEmitter.emit(JitsiTrackEvents.TRACK_AUDIO_LEVEL_CHANGED,
224
+            audioLevel);
225
+        this.audioLevel = audioLevel;
226
+    }
227
+ }
187 228
 
188 229
 module.exports = JitsiTrack;

+ 13
- 62
modules/RTC/RTC.js View File

@@ -9,7 +9,6 @@ var JitsiRemoteTrack = require("./JitsiRemoteTrack.js");
9 9
 var DesktopSharingEventTypes
10 10
     = require("../../service/desktopsharing/DesktopSharingEventTypes");
11 11
 var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
12
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
13 12
 var RTCEvents = require("../../service/RTC/RTCEvents.js");
14 13
 
15 14
 function createLocalTracks(streams) {
@@ -20,10 +19,6 @@ function createLocalTracks(streams) {
20 19
         newStreams.push(localStream);
21 20
         if (streams[i].isMuted === true)
22 21
             localStream.setMute(true);
23
-        //FIXME:
24
-        // var eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CREATED;
25
-        //
26
-        // eventEmitter.emit(eventType, localStream);
27 22
     }
28 23
     return newStreams;
29 24
 }
@@ -31,6 +26,8 @@ function createLocalTracks(streams) {
31 26
 function RTC(room, options) {
32 27
     this.room = room;
33 28
     this.localStreams = [];
29
+    //FIXME: we should start removing those streams.
30
+    //FIXME: We should support multiple streams per jid.
34 31
     this.remoteStreams = {};
35 32
     this.localAudio = null;
36 33
     this.localVideo = null;
@@ -38,12 +35,14 @@ function RTC(room, options) {
38 35
     var self = this;
39 36
     this.options = options || {};
40 37
     room.addPresenceListener("videomuted", function (values, from) {
41
-        if(self.remoteStreams[from])
38
+        if(self.remoteStreams[from]) {
42 39
             self.remoteStreams[from][JitsiTrack.VIDEO].setMute(values.value == "true");
40
+        }
43 41
     });
44 42
     room.addPresenceListener("audiomuted", function (values, from) {
45
-        if(self.remoteStreams[from])
43
+        if(self.remoteStreams[from]) {
46 44
             self.remoteStreams[from][JitsiTrack.AUDIO].setMute(values.value == "true");
45
+        }
47 46
     });
48 47
 }
49 48
 
@@ -104,7 +103,8 @@ RTC.isRTCReady = function () {
104 103
 }
105 104
 
106 105
 RTC.init = function (options) {
107
-    return RTCUtils.init(options || {});
106
+    this.options = options || {};
107
+    return RTCUtils.init(this.options);
108 108
 }
109 109
 
110 110
 RTC.getDeviceAvailability = function () {
@@ -132,8 +132,7 @@ RTC.prototype.removeLocalStream = function (stream) {
132 132
 };
133 133
 
134 134
 RTC.prototype.createRemoteStream = function (data, sid, thessrc) {
135
-    var remoteStream = new JitsiRemoteTrack(this, data, sid, thessrc,
136
-        this.eventEmitter);
135
+    var remoteStream = new JitsiRemoteTrack(this, data, sid, thessrc);
137 136
     if(!data.peerjid)
138 137
         return;
139 138
     var jid = data.peerjid;
@@ -141,7 +140,6 @@ RTC.prototype.createRemoteStream = function (data, sid, thessrc) {
141 140
         this.remoteStreams[jid] = {};
142 141
     }
143 142
     this.remoteStreams[jid][remoteStream.type]= remoteStream;
144
-    this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
145 143
     return remoteStream;
146 144
 };
147 145
 
@@ -193,24 +191,6 @@ RTC.prototype.getVideoElementName = function () {
193 191
 RTC.prototype.dispose = function() {
194 192
 };
195 193
 
196
-RTC.prototype.muteRemoteVideoStream = function (jid, value) {
197
-    var stream;
198
-
199
-    if(this.remoteStreams[jid] &&
200
-        this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
201
-        stream = this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
202
-    }
203
-
204
-    if(!stream)
205
-        return true;
206
-
207
-    if (value != stream.muted) {
208
-        stream.setMute(value);
209
-        return true;
210
-    }
211
-    return false;
212
-};
213
-
214 194
 RTC.prototype.switchVideoStreams = function (newStream) {
215 195
     this.localVideo.stream = newStream;
216 196
 
@@ -222,37 +202,8 @@ RTC.prototype.switchVideoStreams = function (newStream) {
222 202
     this.localStreams.push(this.localVideo);
223 203
 };
224 204
 
225
-RTC.prototype.isVideoMuted = function (jid) {
226
-    if (jid === APP.xmpp.myJid()) {
227
-        var localVideo = APP.RTC.localVideo;
228
-        return (!localVideo || localVideo.isMuted());
229
-    } else {
230
-        if (!this.remoteStreams[jid] ||
231
-            !this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
232
-            return null;
233
-        }
234
-        return this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
235
-    }
236
-};
237
-
238
-RTC.prototype.setVideoMute = function (mute, callback, options) {
239
-    if (!this.localVideo)
240
-        return;
241
-
242
-    if (mute == this.localVideo.isMuted())
243
-    {
244
-        APP.xmpp.sendVideoInfoPresence(mute);
245
-        if (callback)
246
-            callback(mute);
247
-    }
248
-    else
249
-    {
250
-        this.localVideo.setMute(mute);
251
-        this.room.setVideoMute(
252
-            mute,
253
-            callback,
254
-            options);
255
-    }
256
-};
257
-
205
+RTC.prototype.setAudioLevel = function (jid, audioLevel) {
206
+    if(this.remoteStreams[jid] && this.remoteStreams[jid][JitsiTrack.AUDIO])
207
+        this.remoteStreams[jid][JitsiTrack.AUDIO].setAudioLevel(audioLevel);
208
+}
258 209
 module.exports = RTC;

+ 5
- 11
modules/statistics/LocalStatsCollector.js View File

@@ -4,9 +4,6 @@
4 4
  */
5 5
 
6 6
 var RTCBrowserType = require('../RTC/RTCBrowserType');
7
-var StatisticsEvents = require('../../service/statistics/Events');
8
-
9
-var LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
10 7
 
11 8
 /**
12 9
  * Size of the webaudio analyzer buffer.
@@ -67,16 +64,16 @@ function animateLevel(newLevel, lastLevel) {
67 64
  *
68 65
  * @param stream the local stream
69 66
  * @param interval stats refresh interval given in ms.
67
+ * @param callback function that receives the audio levels.
70 68
  * @constructor
71 69
  */
72
-function LocalStatsCollector(stream, interval, statisticsService, eventEmitter) {
70
+function LocalStatsCollector(stream, interval, callback) {
73 71
     window.AudioContext = window.AudioContext || window.webkitAudioContext;
74 72
     this.stream = stream;
75 73
     this.intervalId = null;
76 74
     this.intervalMilis = interval;
77
-    this.eventEmitter = eventEmitter;
78 75
     this.audioLevel = 0;
79
-    this.statisticsService = statisticsService;
76
+    this.callback = callback;
80 77
 }
81 78
 
82 79
 /**
@@ -106,10 +103,7 @@ LocalStatsCollector.prototype.start = function () {
106 103
             var audioLevel = timeDomainDataToAudioLevel(array);
107 104
             if (audioLevel != self.audioLevel) {
108 105
                 self.audioLevel = animateLevel(audioLevel, self.audioLevel);
109
-                self.eventEmitter.emit(
110
-                    StatisticsEvents.AUDIO_LEVEL,
111
-                    self.statisticsService.LOCAL_JID,
112
-                    self.audioLevel);
106
+                self.callback(self.audioLevel);
113 107
             }
114 108
         },
115 109
         this.intervalMilis
@@ -126,4 +120,4 @@ LocalStatsCollector.prototype.stop = function () {
126 120
     }
127 121
 };
128 122
 
129
-module.exports = LocalStatsCollector;
123
+module.exports = LocalStatsCollector;

+ 26
- 17
modules/statistics/statistics.js View File

@@ -18,8 +18,9 @@ var StatisticsEvents = require("../../service/statistics/Events");
18 18
 //    }
19 19
 //}
20 20
 
21
+var eventEmitter = new EventEmitter();
22
+
21 23
 function Statistics() {
22
-    this.localStats = null;
23 24
     this.rtpStats = null;
24 25
     this.eventEmitter = new EventEmitter();
25 26
 }
@@ -33,14 +34,13 @@ Statistics.prototype.startRemoteStats = function (peerconnection) {
33 34
     this.rtpStats.start();
34 35
 }
35 36
 
36
-Statistics.prototype.startLocalStats = function (stream) {
37
-    if(stream.getType() !== "audio")
38
-        return;
39
-    this.localStats = new LocalStats(stream.getOriginalStream(), 200, this,
40
-        this.eventEmitter);
41
-    this.localStats.start();
42
-}
37
+Statistics.localStats = [];
43 38
 
39
+Statistics.startLocalStats = function (stream, callback) {
40
+    var localStats = new LocalStats(stream, 200, callback);
41
+    this.localStats.push(localStats);
42
+    localStats.start();
43
+}
44 44
 
45 45
 Statistics.prototype.addAudioLevelListener = function(listener)
46 46
 {
@@ -53,20 +53,29 @@ Statistics.prototype.removeAudioLevelListener = function(listener)
53 53
 }
54 54
 
55 55
 Statistics.prototype.dispose = function () {
56
-    this.stopLocal();
56
+    Statistics.stopAllLocalStats();
57 57
     this.stopRemote();
58 58
     if(this.eventEmitter)
59
-    {
60 59
         this.eventEmitter.removeAllListeners();
61
-    }
60
+
61
+    if(eventEmitter)
62
+        eventEmitter.removeAllListeners();
62 63
 }
63 64
 
64 65
 
65
-Statistics.prototype.stopLocal = function () {
66
-    if (this.localStats) {
67
-        this.localStats.stop();
68
-        this.localStats = null;
69
-    }
66
+Statistics.stopAllLocalStats = function () {
67
+    for(var i = 0; i < this.localStats.length; i++)
68
+        this.localStats[i].stop();
69
+    this.localStats = [];
70
+}
71
+
72
+Statistics.stopLocalStats = function (stream) {
73
+    for(var i = 0; i < Statistics.localStats.length; i++)
74
+        if(Statistics.localStats[i].stream === stream){
75
+            var localStats = Statistics.localStats.splice(i, 1);
76
+            localStats.stop();
77
+            break;
78
+        }
70 79
 }
71 80
 
72 81
 Statistics.prototype.stopRemote = function () {
@@ -144,4 +153,4 @@ Statistics.LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
144 153
 
145 154
 
146 155
 
147
-module.exports = Statistics;
156
+module.exports = Statistics;

+ 2
- 2
modules/xmpp/ChatRoom.js View File

@@ -515,10 +515,10 @@ ChatRoom.prototype.setJingleSession = function(session){
515 515
 };
516 516
 
517 517
 
518
-ChatRoom.prototype.removeStream = function (stream) {
518
+ChatRoom.prototype.removeStream = function (stream, callback) {
519 519
     if(!this.session)
520 520
         return;
521
-    this.session.peerconnection.removeStream(stream)
521
+    this.session.removeStream(stream, callback);
522 522
 }
523 523
 
524 524
 ChatRoom.prototype.switchStreams = function (stream, oldStream, callback, isAudio) {

+ 37
- 0
modules/xmpp/JingleSessionPC.js View File

@@ -1235,6 +1235,43 @@ JingleSessionPC.prototype.addStream = function (stream, callback) {
1235 1235
     });
1236 1236
 }
1237 1237
 
1238
+/**
1239
+ * Remove streams.
1240
+ * @param stream stream that will be removed.
1241
+ * @param success_callback callback executed after successful stream addition.
1242
+ */
1243
+JingleSessionPC.prototype.removeStream = function (stream, callback) {
1244
+
1245
+    var self = this;
1246
+
1247
+    // Remember SDP to figure out added/removed SSRCs
1248
+    var oldSdp = null;
1249
+    if(this.peerconnection) {
1250
+        if(this.peerconnection.localDescription) {
1251
+            oldSdp = new SDP(this.peerconnection.localDescription.sdp);
1252
+        }
1253
+        if(stream)
1254
+            this.peerconnection.removeStream(stream);
1255
+    }
1256
+
1257
+    // Conference is not active
1258
+    if(!oldSdp || !this.peerconnection) {
1259
+        callback();
1260
+        return;
1261
+    }
1262
+
1263
+    this.addingStreams = true;
1264
+    this.modifySourcesQueue.push(function() {
1265
+        logger.log('modify sources done');
1266
+
1267
+        callback();
1268
+
1269
+        var newSdp = new SDP(self.peerconnection.localDescription.sdp);
1270
+        logger.log("SDPs", oldSdp, newSdp);
1271
+        self.notifyMySSRCUpdate(oldSdp, newSdp);
1272
+    });
1273
+}
1274
+
1238 1275
 /**
1239 1276
  * Figures out added/removed ssrcs and send update IQs.
1240 1277
  * @param old_sdp SDP object for old description.

+ 1
- 2
modules/xmpp/xmpp.js View File

@@ -3,7 +3,6 @@
3 3
 var logger = require("jitsi-meet-logger").getLogger(__filename);
4 4
 var EventEmitter = require("events");
5 5
 var Pako = require("pako");
6
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
7 6
 var RTCEvents = require("../../service/RTC/RTCEvents");
8 7
 var XMPPEvents = require("../../service/xmpp/XMPPEvents");
9 8
 var JitsiConnectionErrors = require("../../JitsiConnectionErrors");
@@ -124,7 +123,7 @@ XMPP.prototype._connect = function (jid, password) {
124 123
                         logger.warn("Ping NOT supported by " + pingJid);
125 124
                 }
126 125
             );
127
-            
126
+
128 127
             if (password)
129 128
                 authenticatedUser = true;
130 129
             if (self.connection && self.connection.connected &&

Loading…
Cancel
Save