浏览代码

Implements audio levels.

tags/v0.0.2
hristoterezov 9 年前
父节点
当前提交
9e0191819a

+ 1
- 0
.gitignore 查看文件

4
 *.iml
4
 *.iml
5
 .*.tmp
5
 .*.tmp
6
 deploy-local.sh
6
 deploy-local.sh
7
+.remote-sync.json

+ 32
- 2
JitsiConference.js 查看文件

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
 var JitsiParticipant = require("./JitsiParticipant");
8
+var Statistics = require("./modules/statistics/statistics");
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.
23
     this.eventEmitter = new EventEmitter();
24
     this.eventEmitter = new EventEmitter();
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);
27
+    if(!options.config.disableAudioLevels)
28
+        this.statistics = new Statistics();
26
     setupListeners(this);
29
     setupListeners(this);
27
     this.participants = {};
30
     this.participants = {};
28
     this.lastActiveSpeaker = null;
31
     this.lastActiveSpeaker = null;
205
  * @param conference the conference
208
  * @param conference the conference
206
  */
209
  */
207
 function setupListeners(conference) {
210
 function setupListeners(conference) {
208
-    conference.xmpp.addListener(XMPPEvents.CALL_INCOMING,
209
-        conference.rtc.onIncommingCall.bind(conference.rtc));
211
+    conference.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
212
+        conference.rtc.onIncommingCall(event);
213
+        if(conference.statistics)
214
+            conference.statistics.startRemoteStats(event.peerconnection);
215
+    });
210
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
216
     conference.room.addListener(XMPPEvents.REMOTE_STREAM_RECEIVED,
211
         conference.rtc.createRemoteStream.bind(conference.rtc));
217
         conference.rtc.createRemoteStream.bind(conference.rtc));
212
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
218
     conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, function (stream) {
255
         conference.eventEmitter.emit(JitsiConferenceEvents.DISPLAY_NAME_CHANGED,
261
         conference.eventEmitter.emit(JitsiConferenceEvents.DISPLAY_NAME_CHANGED,
256
             Strophe.getResourceFromJid(from), displayName);
262
             Strophe.getResourceFromJid(from), displayName);
257
     });
263
     });
264
+
265
+    if(conference.statistics) {
266
+        conference.statistics.addAudioLevelListener(function (ssrc, level) {
267
+            var userId = null;
268
+            if (ssrc === Statistics.LOCAL_JID) {
269
+                userId = conference.myUserId();
270
+            } else {
271
+                var jid = conference.room.getJidBySSRC(ssrc);
272
+                if (!jid)
273
+                    return;
274
+
275
+                userId = Strophe.getResourceFromJid(jid);
276
+            }
277
+            conference.eventEmitter.emit(JitsiConferenceEvents.TRACK_AUDIO_LEVEL_CHANGED,
278
+                userId, level);
279
+        });
280
+        conference.rtc.addListener(StreamEventTypes.EVENT_TYPE_LOCAL_CREATED, function (stream) {
281
+            conference.statistics.startLocalStats(stream);
282
+        });
283
+        conference.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE,
284
+            function () {
285
+                conference.statistics.dispose();
286
+            });
287
+    }
258
 }
288
 }
259
 
289
 
260
 
290
 

+ 34
- 40
doc/API.md 查看文件

40
 
40
 
41
 
41
 
42
 * ```JitsiMeetJS.JitsiConnection``` - the ```JitsiConnection``` constructor. You can use that to create new server connection.
42
 * ```JitsiMeetJS.JitsiConnection``` - the ```JitsiConnection``` constructor. You can use that to create new server connection.
43
- 
43
+
44
 * ```JitsiMeetJS.events``` - JS object that contains all events used by the API. You will need that JS object when you try to subscribe for connection or conference events.
44
 * ```JitsiMeetJS.events``` - JS object that contains all events used by the API. You will need that JS object when you try to subscribe for connection or conference events.
45
     We have two event types - connection and conference. You can access the events with the following code ```JitsiMeetJS.events.<event_type>.<event_name>```.
45
     We have two event types - connection and conference. You can access the events with the following code ```JitsiMeetJS.events.<event_type>.<event_name>```.
46
     For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.events.conference.USER_LEFT```.
46
     For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.events.conference.USER_LEFT```.
48
     1. conference
48
     1. conference
49
         - TRACK_ADDED - remote stream received. (parameters - JitsiTrack)
49
         - TRACK_ADDED - remote stream received. (parameters - JitsiTrack)
50
         - TRACK_REMOVED - remote stream removed. (parameters - JitsiTrack)
50
         - TRACK_REMOVED - remote stream removed. (parameters - JitsiTrack)
51
-        - TRACK_MUTE_CHANGED - JitsiTrack was muted or unmuted. (parameters - JitsiTrack) 
51
+        - TRACK_MUTE_CHANGED - JitsiTrack was muted or unmuted. (parameters - JitsiTrack)
52
         - ACTIVE_SPEAKER_CHANGED - the active speaker is changed. (parameters - id(string))
52
         - ACTIVE_SPEAKER_CHANGED - the active speaker is changed. (parameters - id(string))
53
         - USER_JOINED - new user joined a conference. (parameters - id(string))
53
         - USER_JOINED - new user joined a conference. (parameters - id(string))
54
         - USER_LEFT - a participant left conference. (parameters - id(string))
54
         - USER_LEFT - a participant left conference. (parameters - id(string))
58
         - IN_LAST_N_CHANGED - passes boolean property that shows whether the local user is included in last n set of any other user or not. (parameters - boolean)
58
         - IN_LAST_N_CHANGED - passes boolean property that shows whether the local user is included in last n set of any other user or not. (parameters - boolean)
59
         - CONFERENCE_JOINED - notifies the local user that he joined the conference successfully. (no parameters)
59
         - CONFERENCE_JOINED - notifies the local user that he joined the conference successfully. (no parameters)
60
         - CONFERENCE_LEFT - notifies the local user that he left the conference successfully. (no parameters)
60
         - CONFERENCE_LEFT - notifies the local user that he left the conference successfully. (no parameters)
61
-        
61
+
62
     2. connection
62
     2. connection
63
         - CONNECTION_FAILED - indicates that the server connection failed.
63
         - CONNECTION_FAILED - indicates that the server connection failed.
64
         - CONNECTION_ESTABLISHED - indicates that we have successfully established server connection.
64
         - CONNECTION_ESTABLISHED - indicates that we have successfully established server connection.
65
         - CONNECTION_DISCONNECTED - indicates that we are disconnected.
65
         - CONNECTION_DISCONNECTED - indicates that we are disconnected.
66
         - WRONG_STATE - indicates that the user has performed action that can't be executed because the connection is in wrong state.
66
         - WRONG_STATE - indicates that the user has performed action that can't be executed because the connection is in wrong state.
67
-        
67
+
68
 * ```JitsiMeetJS.errors``` - JS object that contains all errors used by the API. You can use that object to check the reported errors from the API
68
 * ```JitsiMeetJS.errors``` - JS object that contains all errors used by the API. You can use that object to check the reported errors from the API
69
     We have two error types - connection and conference. You can access the events with the following code ```JitsiMeetJS.errors.<error_type>.<error_name>```.
69
     We have two error types - connection and conference. You can access the events with the following code ```JitsiMeetJS.errors.<error_type>.<error_name>```.
70
     For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.errors.conference.PASSWORD_REQUIRED```.
70
     For example if you want to use the conference event that is fired when somebody leave conference you can use the following code - ```JitsiMeetJS.errors.conference.PASSWORD_REQUIRED```.
89
     - appID - identification for the provider of Jitsi Meet video conferencing services. **NOTE: not implemented yet. You can safely pass ```null```**
89
     - appID - identification for the provider of Jitsi Meet video conferencing services. **NOTE: not implemented yet. You can safely pass ```null```**
90
     - token - secret generated by the provider of Jitsi Meet video conferencing services. The token will be send to the provider from the Jitsi Meet server deployment for authorization of the current client. **NOTE: not implemented yet. You can safely pass ```null```**
90
     - token - secret generated by the provider of Jitsi Meet video conferencing services. The token will be send to the provider from the Jitsi Meet server deployment for authorization of the current client. **NOTE: not implemented yet. You can safely pass ```null```**
91
     - options - JS object with configuration options for the server connection. You can change the following properties there:
91
     - options - JS object with configuration options for the server connection. You can change the following properties there:
92
-        1. bosh - 
93
-        2. hosts - JS Object 
92
+        1. bosh -
93
+        2. hosts - JS Object
94
             - domain
94
             - domain
95
             - muc
95
             - muc
96
             - bridge
96
             - bridge
97
             - anonymousdomain
97
             - anonymousdomain
98
-        3. useStunTurn - 
99
-        
98
+        3. useStunTurn -
99
+
100
 2. connect(options) - establish server connection
100
 2. connect(options) - establish server connection
101
     - options - JS Object with ```id``` and ```password``` properties.
101
     - options - JS Object with ```id``` and ```password``` properties.
102
-    
102
+
103
 3. disconnect() - destroys the server connection
103
 3. disconnect() - destroys the server connection
104
 
104
 
105
 4. initJitsiConference(name, options) - creates new ```JitsiConference``` object.
105
 4. initJitsiConference(name, options) - creates new ```JitsiConference``` object.
106
     - name - the name of the conference
106
     - name - the name of the conference
107
     - options - JS object with configuration options for the conference. You can change the following properties there:
107
     - options - JS object with configuration options for the conference. You can change the following properties there:
108
-        1. devices - array with the devices - "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices. 
108
+        1. devices - array with the devices - "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices.
109
         2. resolution - the prefered resolution for the local video.
109
         2. resolution - the prefered resolution for the local video.
110
         3. openSctp - boolean property. Enables/disables datachannel support. **NOTE: we recommend to set that option to true**
110
         3. openSctp - boolean property. Enables/disables datachannel support. **NOTE: we recommend to set that option to true**
111
+        4. disableAudioLevels - boolean property. Enables/disables audio levels. 
111
 
112
 
112
 5. addEventListener(event, listener) - Subscribes the passed listener to the event.
113
 5. addEventListener(event, listener) - Subscribes the passed listener to the event.
113
     - event - one of the events from ```JitsiMeetJS.events.connection``` object.
114
     - event - one of the events from ```JitsiMeetJS.events.connection``` object.
114
     - listener - handler for the event.
115
     - listener - handler for the event.
115
-    
116
+
116
 6. removeEventListener(event, listener) - Removes event listener.
117
 6. removeEventListener(event, listener) - Removes event listener.
117
     - event - the event
118
     - event - the event
118
     - listener - the listener that will be removed.
119
     - listener - the listener that will be removed.
124
 
125
 
125
 1. join(password) - Joins the conference
126
 1. join(password) - Joins the conference
126
     - password - string of the password. This parameter is not mandatory.
127
     - password - string of the password. This parameter is not mandatory.
127
-    
128
+
128
 2. leave() - leaves the conference
129
 2. leave() - leaves the conference
129
 
130
 
130
 3. createLocalTracks(options) - Creates the media tracks and returns them trough ```Promise``` object.
131
 3. createLocalTracks(options) - Creates the media tracks and returns them trough ```Promise``` object.
131
     - options - JS object with configuration options for the local media tracks. You can change the following properties there:
132
     - options - JS object with configuration options for the local media tracks. You can change the following properties there:
132
-        1. devices - array with the devices - "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices. 
133
+        1. devices - array with the devices - "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices.
133
         2. resolution - the prefered resolution for the local video.
134
         2. resolution - the prefered resolution for the local video.
134
-        
135
+
135
 4. getLocalTracks() - Returns array with JitsiTrack objects for the local streams.
136
 4. getLocalTracks() - Returns array with JitsiTrack objects for the local streams.
136
 
137
 
137
 5. addEventListener(event, listener) - Subscribes the passed listener to the event.
138
 5. addEventListener(event, listener) - Subscribes the passed listener to the event.
138
     - event - one of the events from ```JitsiMeetJS.events.conference``` object.
139
     - event - one of the events from ```JitsiMeetJS.events.conference``` object.
139
     - listener - handler for the event.
140
     - listener - handler for the event.
140
-    
141
+
141
 6. removeEventListener(event, listener) - Removes event listener.
142
 6. removeEventListener(event, listener) - Removes event listener.
142
     - event - the event
143
     - event - the event
143
     - listener - the listener that will be removed.
144
     - listener - the listener that will be removed.
144
-    
145
+
145
 7. on(event, listener) - alias for addEventListener
146
 7. on(event, listener) - alias for addEventListener
146
 
147
 
147
 8. off(event, listener) - alias for removeEventListener
148
 8. off(event, listener) - alias for removeEventListener
157
 12. sendCommand(name, values) - sends user defined system command to the other participants
158
 12. sendCommand(name, values) - sends user defined system command to the other participants
158
     - name - the name of the command.
159
     - name - the name of the command.
159
     - values - JS object. The object has the following structure:
160
     - values - JS object. The object has the following structure:
160
-    
161
-    
161
+
162
+
162
         ```
163
         ```
163
             {
164
             {
164
-            
165
-            
165
+
166
+
166
                 value: the_value_of_the_command,
167
                 value: the_value_of_the_command,
167
-                
168
-                
168
+
169
+
169
                 attributes: {},// map with keys the name of the attribute and values - the values of the attributes.
170
                 attributes: {},// map with keys the name of the attribute and values - the values of the attributes.
170
-                
171
-                
171
+
172
+
172
                 children: [] // array with JS object with the same structure.
173
                 children: [] // array with JS object with the same structure.
173
             }
174
             }
174
         ```
175
         ```
175
-        
176
-        
176
+
177
+
177
     NOTE: When you use that method the passed object will be added in every system message that is sent to the other participants. It might be sent more than once.
178
     NOTE: When you use that method the passed object will be added in every system message that is sent to the other participants. It might be sent more than once.
178
 
179
 
179
 
180
 
185
 
186
 
186
 15. addCommandListener(command, handler) - adds listener
187
 15. addCommandListener(command, handler) - adds listener
187
     - command - string for the name of the command
188
     - command - string for the name of the command
188
-    - handler(values) - the listener that will be called when a command is received from another participant. 
189
+    - handler(values) - the listener that will be called when a command is received from another participant.
189
 
190
 
190
 16. removeCommandListener(command) - removes the listeners for the specified command
191
 16. removeCommandListener(command) - removes the listeners for the specified command
191
     - command - the name of the command
192
     - command - the name of the command
192
-    
193
+
193
 
194
 
194
 JitsiTrack
195
 JitsiTrack
195
 ======
196
 ======
199
 1.getType() - returns string with the type of the track( "video" for the video tracks and "audio" for the audio tracks)
200
 1.getType() - returns string with the type of the track( "video" for the video tracks and "audio" for the audio tracks)
200
 
201
 
201
 
202
 
202
-2.mute() - mutes the track. 
203
+2.mute() - mutes the track.
203
 
204
 
204
 Note: This method is implemented only for the local tracks.
205
 Note: This method is implemented only for the local tracks.
205
 
206
 
206
 
207
 
207
-3.unmute() - unmutes the track. 
208
+3.unmute() - unmutes the track.
208
 
209
 
209
 Note: This method is implemented only for the local tracks.
210
 Note: This method is implemented only for the local tracks.
210
 
211
 
211
 
212
 
212
 4. attach(container) - attaches the track to the given container.
213
 4. attach(container) - attaches the track to the given container.
213
- 
214
+
214
 5. detach(container) - removes the track from the container.
215
 5. detach(container) - removes the track from the container.
215
 
216
 
216
 6. stop() - stop sending the track to the other participants in the conference.
217
 6. stop() - stop sending the track to the other participants in the conference.
224
 8. getId() - returns unique string for the track.
225
 8. getId() - returns unique string for the track.
225
 
226
 
226
 
227
 
227
-        
228
+
228
 Getting Started
229
 Getting Started
229
 ==============
230
 ==============
230
 
231
 
252
 connection.connect();
253
 connection.connect();
253
 ```
254
 ```
254
 
255
 
255
-4. After you receive the ```CONNECTION_ESTABLISHED``` event you are to create the ```JitsiConference``` object and 
256
+4. After you receive the ```CONNECTION_ESTABLISHED``` event you are to create the ```JitsiConference``` object and
256
 also you may want to attach listeners for conference events (we are going to add handlers for remote track, conference joined, etc. ):
257
 also you may want to attach listeners for conference events (we are going to add handlers for remote track, conference joined, etc. ):
257
 
258
 
258
 
259
 
277
 ```
278
 ```
278
 
279
 
279
 After that step you are in the conference. Now you can continue with adding some code that will handle the events and manage the conference.
280
 After that step you are in the conference. Now you can continue with adding some code that will handle the events and manage the conference.
280
-
281
-
282
-
283
-
284
-
285
-
286
-

+ 6
- 6
doc/example/example.js 查看文件

19
 }
19
 }
20
 
20
 
21
 var confOptions = {
21
 var confOptions = {
22
-    openSctp: true
22
+    openSctp: true,
23
+    disableAudioLevels: true
23
 }
24
 }
24
 
25
 
25
 /**
26
 /**
29
 function onLocalTracks(tracks)
30
 function onLocalTracks(tracks)
30
 {
31
 {
31
     localTracks = tracks;
32
     localTracks = tracks;
32
-    console.log(tracks);
33
     tracks[0].attach($("#localAudio"));
33
     tracks[0].attach($("#localAudio"));
34
     tracks[1].attach($("#localVideo"));
34
     tracks[1].attach($("#localVideo"));
35
     for(var i = 0; i < localTracks.length; i++)
35
     for(var i = 0; i < localTracks.length; i++)
90
     room.on(JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED, function (userID, displayName) {
90
     room.on(JitsiMeetJS.events.conference.DISPLAY_NAME_CHANGED, function (userID, displayName) {
91
         console.debug(userID + " - " + displayName);
91
         console.debug(userID + " - " + displayName);
92
     });
92
     });
93
+    room.on(JitsiMeetJS.events.conference.TRACK_AUDIO_LEVEL_CHANGED,
94
+      function(userID, audioLevel){
95
+          // console.log(userID + " - " + audioLevel);
96
+      });
93
     room.join();
97
     room.join();
94
 };
98
 };
95
 
99
 
128
 connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED, disconnect);
132
 connection.addEventListener(JitsiMeetJS.events.connection.CONNECTION_DISCONNECTED, disconnect);
129
 
133
 
130
 connection.connect();
134
 connection.connect();
131
-
132
-
133
-
134
-

+ 1
- 1
doc/example/index.html 查看文件

15
     <video id="localVideo" autoplay="true"></video>
15
     <video id="localVideo" autoplay="true"></video>
16
     <!--<audio id="localAudio" autoplay="true" muted="true"></audio>-->
16
     <!--<audio id="localAudio" autoplay="true" muted="true"></audio>-->
17
 </body>
17
 </body>
18
-</html>
18
+</html>

+ 7481
- 6430
lib-jitsi-meet.js
文件差异内容过多而无法显示
查看文件


+ 1
- 12
modules/RTC/RTC.js 查看文件

104
         this.dataChannels.handlePinnedEndpointEvent(id);
104
         this.dataChannels.handlePinnedEndpointEvent(id);
105
 }
105
 }
106
 
106
 
107
-RTC.prototype.addStreamListener = function (listener, eventType) {
108
-    this.eventEmitter.on(eventType, listener);
109
-};
110
-
111
 RTC.prototype.addListener = function (type, listener) {
107
 RTC.prototype.addListener = function (type, listener) {
112
     this.eventEmitter.on(type, listener);
108
     this.eventEmitter.on(type, listener);
113
 };
109
 };
114
 
110
 
115
-RTC.prototype.removeListener = function (listener, eventType) {
116
-    this.eventEmitter.removeListener(eventType, listener);
117
-};
118
-
119
-RTC.prototype.removeStreamListener = function (listener, eventType) {
120
-    if(!(eventType instanceof StreamEventTypes))
121
-        throw "Illegal argument";
122
-
111
+RTC.prototype.removeListener = function (eventType, listener) {
123
     this.eventEmitter.removeListener(eventType, listener);
112
     this.eventEmitter.removeListener(eventType, listener);
124
 };
113
 };
125
 
114
 

+ 4
- 2
modules/statistics/LocalStatsCollector.js 查看文件

5
 
5
 
6
 var RTCBrowserType = require('../RTC/RTCBrowserType');
6
 var RTCBrowserType = require('../RTC/RTCBrowserType');
7
 
7
 
8
+var LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
9
+
8
 /**
10
 /**
9
  * Size of the webaudio analyzer buffer.
11
  * Size of the webaudio analyzer buffer.
10
  * @type {number}
12
  * @type {number}
80
  * Starts the collecting the statistics.
82
  * Starts the collecting the statistics.
81
  */
83
  */
82
 LocalStatsCollector.prototype.start = function () {
84
 LocalStatsCollector.prototype.start = function () {
83
-    if (config.disableAudioLevels || !window.AudioContext ||
85
+    if (!window.AudioContext ||
84
         RTCBrowserType.isTemasysPluginUsed())
86
         RTCBrowserType.isTemasysPluginUsed())
85
         return;
87
         return;
86
 
88
 
105
                 self.audioLevel = animateLevel(audioLevel, self.audioLevel);
107
                 self.audioLevel = animateLevel(audioLevel, self.audioLevel);
106
                 self.eventEmitter.emit(
108
                 self.eventEmitter.emit(
107
                     "statistics.audioLevel",
109
                     "statistics.audioLevel",
108
-                    self.statisticsService.LOCAL_JID,
110
+                    LOCAL_JID,
109
                     self.audioLevel);
111
                     self.audioLevel);
110
             }
112
             }
111
         },
113
         },

+ 232
- 231
modules/statistics/RTPStatsCollector.js 查看文件

5
 /* Whether we support the browser we are running into for logging statistics */
5
 /* Whether we support the browser we are running into for logging statistics */
6
 var browserSupported = RTCBrowserType.isChrome() ||
6
 var browserSupported = RTCBrowserType.isChrome() ||
7
     RTCBrowserType.isOpera();
7
     RTCBrowserType.isOpera();
8
+
9
+var keyMap = {};
10
+keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
11
+    "ssrc": "ssrc",
12
+    "packetsReceived": "packetsReceived",
13
+    "packetsLost": "packetsLost",
14
+    "packetsSent": "packetsSent",
15
+    "bytesReceived": "bytesReceived",
16
+    "bytesSent": "bytesSent"
17
+};
18
+keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
19
+    "receiveBandwidth": "googAvailableReceiveBandwidth",
20
+    "sendBandwidth": "googAvailableSendBandwidth",
21
+    "remoteAddress": "googRemoteAddress",
22
+    "transportType": "googTransportType",
23
+    "localAddress": "googLocalAddress",
24
+    "activeConnection": "googActiveConnection",
25
+    "ssrc": "ssrc",
26
+    "packetsReceived": "packetsReceived",
27
+    "packetsSent": "packetsSent",
28
+    "packetsLost": "packetsLost",
29
+    "bytesReceived": "bytesReceived",
30
+    "bytesSent": "bytesSent",
31
+    "googFrameHeightReceived": "googFrameHeightReceived",
32
+    "googFrameWidthReceived": "googFrameWidthReceived",
33
+    "googFrameHeightSent": "googFrameHeightSent",
34
+    "googFrameWidthSent": "googFrameWidthSent",
35
+    "audioInputLevel": "audioInputLevel",
36
+    "audioOutputLevel": "audioOutputLevel"
37
+};
38
+keyMap[RTCBrowserType.RTC_BROWSER_OPERA] =
39
+    keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
40
+
8
 /**
41
 /**
9
  * Calculates packet lost percent using the number of lost packets and the
42
  * Calculates packet lost percent using the number of lost packets and the
10
  * number of all packet.
43
  * number of all packet.
27
         item.stat(key) : item[key];
60
         item.stat(key) : item[key];
28
 }
61
 }
29
 
62
 
63
+function formatAudioLevel(audioLevel) {
64
+    return Math.min(Math.max(audioLevel, 0), 1);
65
+}
66
+
67
+/**
68
+ * Checks whether a certain record should be included in the logged statistics.
69
+ */
70
+function acceptStat(reportId, reportType, statName) {
71
+    if (reportType == "googCandidatePair" && statName == "googChannelId")
72
+        return false;
73
+
74
+    if (reportType == "ssrc") {
75
+        if (statName == "googTrackId" ||
76
+            statName == "transportId" ||
77
+            statName == "ssrc")
78
+            return false;
79
+    }
80
+
81
+    return true;
82
+}
83
+
84
+/**
85
+ * Checks whether a certain record should be included in the logged statistics.
86
+ */
87
+function acceptReport(id, type) {
88
+    if (id.substring(0, 15) == "googCertificate" ||
89
+        id.substring(0, 9) == "googTrack" ||
90
+        id.substring(0, 20) == "googLibjingleSession")
91
+        return false;
92
+
93
+    if (type == "googComponent")
94
+        return false;
95
+
96
+    return true;
97
+}
98
+
30
 /**
99
 /**
31
  * Peer statistics data holder.
100
  * Peer statistics data holder.
32
  * @constructor
101
  * @constructor
39
     this.ssrc2resolution = {};
108
     this.ssrc2resolution = {};
40
 }
109
 }
41
 
110
 
42
-/**
43
- * The bandwidth
44
- * @type {{}}
45
- */
46
-PeerStats.bandwidth = {};
47
-
48
-/**
49
- * The bit rate
50
- * @type {{}}
51
- */
52
-PeerStats.bitrate = {};
53
-
54
-/**
55
- * The packet loss rate
56
- * @type {{}}
57
- */
58
-PeerStats.packetLoss = null;
59
-
60
 /**
111
 /**
61
  * Sets packets loss rate for given <tt>ssrc</tt> that blong to the peer
112
  * Sets packets loss rate for given <tt>ssrc</tt> that blong to the peer
62
  * represented by this instance.
113
  * represented by this instance.
63
- * @param ssrc audio or video RTP stream SSRC.
64
  * @param lossRate new packet loss rate value to be set.
114
  * @param lossRate new packet loss rate value to be set.
65
  */
115
  */
66
-PeerStats.prototype.setSsrcLoss = function (ssrc, lossRate)
116
+PeerStats.prototype.setSsrcLoss = function (lossRate)
67
 {
117
 {
68
-    this.ssrc2Loss[ssrc] = lossRate;
118
+    this.ssrc2Loss = lossRate;
69
 };
119
 };
70
 
120
 
71
 /**
121
 /**
72
- * Sets resolution for given <tt>ssrc</tt> that belong to the peer
122
+ * Sets resolution that belong to the ssrc
73
  * represented by this instance.
123
  * represented by this instance.
74
- * @param ssrc audio or video RTP stream SSRC.
75
  * @param resolution new resolution value to be set.
124
  * @param resolution new resolution value to be set.
76
  */
125
  */
77
-PeerStats.prototype.setSsrcResolution = function (ssrc, resolution)
126
+PeerStats.prototype.setSsrcResolution = function (resolution)
78
 {
127
 {
79
     if(resolution === null && this.ssrc2resolution[ssrc])
128
     if(resolution === null && this.ssrc2resolution[ssrc])
80
     {
129
     {
116
     this.ssrc2AudioLevel[ssrc] = formatAudioLevel(audioLevel);
165
     this.ssrc2AudioLevel[ssrc] = formatAudioLevel(audioLevel);
117
 };
166
 };
118
 
167
 
119
-function formatAudioLevel(audioLevel) {
120
-    return Math.min(Math.max(audioLevel, 0), 1);
121
-}
168
+function ConferenceStats() {
122
 
169
 
123
-/**
124
- * Array with the transport information.
125
- * @type {Array}
126
- */
127
-PeerStats.transport = [];
128
 
170
 
171
+    /**
172
+     * The bandwidth
173
+     * @type {{}}
174
+     */
175
+    this.bandwidth = {};
176
+
177
+    /**
178
+     * The bit rate
179
+     * @type {{}}
180
+     */
181
+    this.bitrate = {};
182
+
183
+    /**
184
+     * The packet loss rate
185
+     * @type {{}}
186
+     */
187
+    this.packetLoss = null;
188
+
189
+
190
+    /**
191
+     * Array with the transport information.
192
+     * @type {Array}
193
+     */
194
+    this.transport = [];
195
+}
129
 
196
 
130
 /**
197
 /**
131
  * <tt>StatsCollector</tt> registers for stats updates of given
198
  * <tt>StatsCollector</tt> registers for stats updates of given
138
  * @param interval stats refresh interval given in ms.
205
  * @param interval stats refresh interval given in ms.
139
  * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
206
  * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
140
  * called on stats update.
207
  * called on stats update.
208
+ * @param config {object} supports the following properties - disableAudioLevels, disableStats, logStats
141
  * @constructor
209
  * @constructor
142
  */
210
  */
143
-function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter)
211
+function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter, config)
144
 {
212
 {
145
     this.peerconnection = peerconnection;
213
     this.peerconnection = peerconnection;
146
     this.baselineAudioLevelsReport = null;
214
     this.baselineAudioLevelsReport = null;
149
     this.baselineStatsReport = null;
217
     this.baselineStatsReport = null;
150
     this.audioLevelsIntervalId = null;
218
     this.audioLevelsIntervalId = null;
151
     this.eventEmitter = eventEmitter;
219
     this.eventEmitter = eventEmitter;
220
+    this.config = config || {};
221
+    this.conferenceStats = new ConferenceStats();
152
 
222
 
153
     /**
223
     /**
154
      * Gather PeerConnection stats once every this many milliseconds.
224
      * Gather PeerConnection stats once every this many milliseconds.
185
 
255
 
186
     this.statsIntervalId = null;
256
     this.statsIntervalId = null;
187
     this.statsIntervalMilis = statsInterval;
257
     this.statsIntervalMilis = statsInterval;
188
-    // Map of jids to PeerStats
189
-    this.jid2stats = {};
258
+    // Map of ssrcs to PeerStats
259
+    this.ssrc2stats = {};
190
 }
260
 }
191
 
261
 
192
 module.exports = StatsCollector;
262
 module.exports = StatsCollector;
235
 StatsCollector.prototype.start = function ()
305
 StatsCollector.prototype.start = function ()
236
 {
306
 {
237
     var self = this;
307
     var self = this;
238
-    if (!config.disableAudioLevels) {
239
-        this.audioLevelsIntervalId = setInterval(
240
-            function () {
241
-                // Interval updates
242
-                self.peerconnection.getStats(
243
-                    function (report) {
244
-                        var results = null;
245
-                        if (!report || !report.result ||
246
-                            typeof report.result != 'function') {
247
-                            results = report;
248
-                        }
249
-                        else {
250
-                            results = report.result();
251
-                        }
252
-                        //console.error("Got interval report", results);
253
-                        self.currentAudioLevelsReport = results;
254
-                        self.processAudioLevelReport();
255
-                        self.baselineAudioLevelsReport =
256
-                            self.currentAudioLevelsReport;
257
-                    },
258
-                    self.errorCallback
259
-                );
260
-            },
261
-            self.audioLevelsIntervalMilis
262
-        );
263
-    }
264
-
265
-    if (!config.disableStats && browserSupported) {
266
-        this.statsIntervalId = setInterval(
267
-            function () {
268
-                // Interval updates
269
-                self.peerconnection.getStats(
270
-                    function (report) {
271
-                        var results = null;
272
-                        if (!report || !report.result ||
273
-                            typeof report.result != 'function') {
274
-                            //firefox
275
-                            results = report;
276
-                        }
277
-                        else {
278
-                            //chrome
279
-                            results = report.result();
280
-                        }
281
-                        //console.error("Got interval report", results);
282
-                        self.currentStatsReport = results;
283
-                        try {
284
-                            self.processStatsReport();
285
-                        }
286
-                        catch (e) {
287
-                            console.error("Unsupported key:" + e, e);
288
-                        }
289
-
290
-                        self.baselineStatsReport = self.currentStatsReport;
291
-                    },
292
-                    self.errorCallback
293
-                );
294
-            },
295
-            self.statsIntervalMilis
296
-        );
297
-    }
298
-
299
-    if (config.logStats && browserSupported) {
300
-        this.gatherStatsIntervalId = setInterval(
301
-            function () {
302
-                self.peerconnection.getStats(
303
-                    function (report) {
304
-                        self.addStatsToBeLogged(report.result());
305
-                    },
306
-                    function () {
308
+    this.audioLevelsIntervalId = setInterval(
309
+        function () {
310
+            // Interval updates
311
+            self.peerconnection.getStats(
312
+                function (report) {
313
+                    var results = null;
314
+                    if (!report || !report.result ||
315
+                        typeof report.result != 'function') {
316
+                        results = report;
307
                     }
317
                     }
308
-                );
309
-            },
310
-            this.GATHER_INTERVAL
311
-        );
312
-
313
-        this.logStatsIntervalId = setInterval(
314
-            function() { self.logStats(); },
315
-            this.LOG_INTERVAL);
316
-    }
317
-};
318
-
319
-/**
320
- * Checks whether a certain record should be included in the logged statistics.
321
- */
322
-function acceptStat(reportId, reportType, statName) {
323
-    if (reportType == "googCandidatePair" && statName == "googChannelId")
324
-        return false;
325
-
326
-    if (reportType == "ssrc") {
327
-        if (statName == "googTrackId" ||
328
-            statName == "transportId" ||
329
-            statName == "ssrc")
330
-            return false;
331
-    }
332
-
333
-    return true;
334
-}
335
-
336
-/**
337
- * Checks whether a certain record should be included in the logged statistics.
338
- */
339
-function acceptReport(id, type) {
340
-    if (id.substring(0, 15) == "googCertificate" ||
341
-        id.substring(0, 9) == "googTrack" ||
342
-        id.substring(0, 20) == "googLibjingleSession")
343
-        return false;
344
-
345
-    if (type == "googComponent")
346
-        return false;
318
+                    else {
319
+                        results = report.result();
320
+                    }
321
+                    //console.error("Got interval report", results);
322
+                    self.currentAudioLevelsReport = results;
323
+                    self.processAudioLevelReport();
324
+                    self.baselineAudioLevelsReport =
325
+                        self.currentAudioLevelsReport;
326
+                },
327
+                self.errorCallback
328
+            );
329
+        },
330
+        self.audioLevelsIntervalMilis
331
+    );
347
 
332
 
348
-    return true;
349
-}
333
+//    if (!this.config.disableStats && browserSupported) {
334
+//        this.statsIntervalId = setInterval(
335
+//            function () {
336
+//                // Interval updates
337
+//                self.peerconnection.getStats(
338
+//                    function (report) {
339
+//                        var results = null;
340
+//                        if (!report || !report.result ||
341
+//                            typeof report.result != 'function') {
342
+//                            //firefox
343
+//                            results = report;
344
+//                        }
345
+//                        else {
346
+//                            //chrome
347
+//                            results = report.result();
348
+//                        }
349
+//                        //console.error("Got interval report", results);
350
+//                        self.currentStatsReport = results;
351
+//                        try {
352
+//                            self.processStatsReport();
353
+//                        }
354
+//                        catch (e) {
355
+//                            console.error("Unsupported key:" + e, e);
356
+//                        }
357
+//
358
+//                        self.baselineStatsReport = self.currentStatsReport;
359
+//                    },
360
+//                    self.errorCallback
361
+//                );
362
+//            },
363
+//            self.statsIntervalMilis
364
+//        );
365
+//    }
366
+//
367
+//    if (this.config.logStats && browserSupported) {
368
+//        this.gatherStatsIntervalId = setInterval(
369
+//            function () {
370
+//                self.peerconnection.getStats(
371
+//                    function (report) {
372
+//                        self.addStatsToBeLogged(report.result());
373
+//                    },
374
+//                    function () {
375
+//                    }
376
+//                );
377
+//            },
378
+//            this.GATHER_INTERVAL
379
+//        );
380
+//
381
+//        this.logStatsIntervalId = setInterval(
382
+//            function() { self.logStats(); },
383
+//            this.LOG_INTERVAL);
384
+//    }
385
+};
350
 
386
 
351
 /**
387
 /**
352
  * Converts the stats to the format used for logging, and saves the data in
388
  * Converts the stats to the format used for logging, and saves the data in
380
     });
416
     });
381
 };
417
 };
382
 
418
 
383
-StatsCollector.prototype.logStats = function () {
384
 
419
 
385
-    if(!APP.xmpp.sendLogs(this.statsToBeLogged))
386
-        return;
387
-    // Reset the stats
388
-    this.statsToBeLogged.stats = {};
389
-    this.statsToBeLogged.timestamps = [];
390
-};
391
-var keyMap = {};
392
-keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
393
-    "ssrc": "ssrc",
394
-    "packetsReceived": "packetsReceived",
395
-    "packetsLost": "packetsLost",
396
-    "packetsSent": "packetsSent",
397
-    "bytesReceived": "bytesReceived",
398
-    "bytesSent": "bytesSent"
399
-};
400
-keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
401
-    "receiveBandwidth": "googAvailableReceiveBandwidth",
402
-    "sendBandwidth": "googAvailableSendBandwidth",
403
-    "remoteAddress": "googRemoteAddress",
404
-    "transportType": "googTransportType",
405
-    "localAddress": "googLocalAddress",
406
-    "activeConnection": "googActiveConnection",
407
-    "ssrc": "ssrc",
408
-    "packetsReceived": "packetsReceived",
409
-    "packetsSent": "packetsSent",
410
-    "packetsLost": "packetsLost",
411
-    "bytesReceived": "bytesReceived",
412
-    "bytesSent": "bytesSent",
413
-    "googFrameHeightReceived": "googFrameHeightReceived",
414
-    "googFrameWidthReceived": "googFrameWidthReceived",
415
-    "googFrameHeightSent": "googFrameHeightSent",
416
-    "googFrameWidthSent": "googFrameWidthSent",
417
-    "audioInputLevel": "audioInputLevel",
418
-    "audioOutputLevel": "audioOutputLevel"
419
-};
420
-keyMap[RTCBrowserType.RTC_BROWSER_OPERA] =
421
-    keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
420
+//FIXME:
421
+//StatsCollector.prototype.logStats = function () {
422
+//
423
+//    if(!APP.xmpp.sendLogs(this.statsToBeLogged))
424
+//        return;
425
+//    // Reset the stats
426
+//    this.statsToBeLogged.stats = {};
427
+//    this.statsToBeLogged.timestamps = [];
428
+//};
422
 
429
 
423
 
430
 
424
 /**
431
 /**
434
         try {
441
         try {
435
             if (getStatValue(now, 'receiveBandwidth') ||
442
             if (getStatValue(now, 'receiveBandwidth') ||
436
                 getStatValue(now, 'sendBandwidth')) {
443
                 getStatValue(now, 'sendBandwidth')) {
437
-                PeerStats.bandwidth = {
444
+                this.conferenceStats.bandwidth = {
438
                     "download": Math.round(
445
                     "download": Math.round(
439
                             (getStatValue(now, 'receiveBandwidth')) / 1000),
446
                             (getStatValue(now, 'receiveBandwidth')) / 1000),
440
                     "upload": Math.round(
447
                     "upload": Math.round(
457
             if(!ip || !type || !localIP || active != "true")
464
             if(!ip || !type || !localIP || active != "true")
458
                 continue;
465
                 continue;
459
             var addressSaved = false;
466
             var addressSaved = false;
460
-            for(var i = 0; i < PeerStats.transport.length; i++)
467
+            for(var i = 0; i < this.conferenceStats.transport.length; i++)
461
             {
468
             {
462
-                if(PeerStats.transport[i].ip == ip &&
463
-                    PeerStats.transport[i].type == type &&
464
-                    PeerStats.transport[i].localip == localIP)
469
+                if(this.conferenceStats.transport[i].ip == ip &&
470
+                    this.conferenceStats.transport[i].type == type &&
471
+                    this.conferenceStats.transport[i].localip == localIP)
465
                 {
472
                 {
466
                     addressSaved = true;
473
                     addressSaved = true;
467
                 }
474
                 }
468
             }
475
             }
469
             if(addressSaved)
476
             if(addressSaved)
470
                 continue;
477
                 continue;
471
-            PeerStats.transport.push({localip: localIP, ip: ip, type: type});
478
+            this.conferenceStats.transport.push({localip: localIP, ip: ip, type: type});
472
             continue;
479
             continue;
473
         }
480
         }
474
 
481
 
479
 
486
 
480
             var local = this.currentStatsReport[now.localCandidateId];
487
             var local = this.currentStatsReport[now.localCandidateId];
481
             var remote = this.currentStatsReport[now.remoteCandidateId];
488
             var remote = this.currentStatsReport[now.remoteCandidateId];
482
-            PeerStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
489
+            this.conferenceStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
483
                 ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
490
                 ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
484
 
491
 
485
         }
492
         }
498
         var ssrc = getStatValue(now, 'ssrc');
505
         var ssrc = getStatValue(now, 'ssrc');
499
         if(!ssrc)
506
         if(!ssrc)
500
             continue;
507
             continue;
501
-        var jid = APP.xmpp.getJidFromSSRC(ssrc);
502
-        if (!jid && (Date.now() - now.timestamp) < 3000) {
503
-            console.warn("No jid for ssrc: " + ssrc);
504
-            continue;
505
-        }
506
 
508
 
507
-        var jidStats = this.jid2stats[jid];
508
-        if (!jidStats) {
509
-            jidStats = new PeerStats();
510
-            this.jid2stats[jid] = jidStats;
509
+        var ssrcStats = this.ssrc2stats[ssrc];
510
+        if (!ssrcStats) {
511
+            ssrcStats = new PeerStats();
512
+            this.ssrc2stats[ssrc] = ssrcStats;
511
         }
513
         }
512
 
514
 
513
 
515
 
544
             lossRate = 0;
546
             lossRate = 0;
545
         var packetsTotal = (packetRate + lossRate);
547
         var packetsTotal = (packetRate + lossRate);
546
 
548
 
547
-        jidStats.setSsrcLoss(ssrc,
549
+        ssrcStats.setSsrcLoss(ssrc,
548
             {"packetsTotal": packetsTotal,
550
             {"packetsTotal": packetsTotal,
549
                 "packetsLost": lossRate,
551
                 "packetsLost": lossRate,
550
                 "isDownloadStream": isDownloadStream});
552
                 "isDownloadStream": isDownloadStream});
582
             bytesSent = Math.round(((bytesSent * 8) / time) / 1000);
584
             bytesSent = Math.round(((bytesSent * 8) / time) / 1000);
583
         }
585
         }
584
 
586
 
585
-        jidStats.setSsrcBitrate(ssrc, {
587
+        ssrcStats.setSsrcBitrate(ssrc, {
586
             "download": bytesReceived,
588
             "download": bytesReceived,
587
             "upload": bytesSent});
589
             "upload": bytesSent});
588
 
590
 
603
 
605
 
604
         if(resolution.height && resolution.width)
606
         if(resolution.height && resolution.width)
605
         {
607
         {
606
-            jidStats.setSsrcResolution(ssrc, resolution);
608
+            ssrcStats.setSsrcResolution(ssrc, resolution);
607
         }
609
         }
608
         else
610
         else
609
         {
611
         {
610
-            jidStats.setSsrcResolution(ssrc, null);
612
+            ssrcStats.setSsrcResolution(ssrc, null);
611
         }
613
         }
612
 
614
 
613
 
615
 
620
     var bitrateDownload = 0;
622
     var bitrateDownload = 0;
621
     var bitrateUpload = 0;
623
     var bitrateUpload = 0;
622
     var resolutions = {};
624
     var resolutions = {};
623
-    Object.keys(this.jid2stats).forEach(
625
+    Object.keys(this.ssrc2stats).forEach(
624
         function (jid)
626
         function (jid)
625
         {
627
         {
626
-            Object.keys(self.jid2stats[jid].ssrc2Loss).forEach(
628
+            Object.keys(self.ssrc2stats[jid].ssrc2Loss).forEach(
627
                 function (ssrc)
629
                 function (ssrc)
628
                 {
630
                 {
629
                     var type = "upload";
631
                     var type = "upload";
630
-                    if(self.jid2stats[jid].ssrc2Loss[ssrc].isDownloadStream)
632
+                    if(self.ssrc2stats[jid].ssrc2Loss[ssrc].isDownloadStream)
631
                         type = "download";
633
                         type = "download";
632
                     totalPackets[type] +=
634
                     totalPackets[type] +=
633
-                        self.jid2stats[jid].ssrc2Loss[ssrc].packetsTotal;
635
+                        self.ssrc2stats[jid].ssrc2Loss[ssrc].packetsTotal;
634
                     lostPackets[type] +=
636
                     lostPackets[type] +=
635
-                        self.jid2stats[jid].ssrc2Loss[ssrc].packetsLost;
637
+                        self.ssrc2stats[jid].ssrc2Loss[ssrc].packetsLost;
636
                 }
638
                 }
637
             );
639
             );
638
-            Object.keys(self.jid2stats[jid].ssrc2bitrate).forEach(
640
+            Object.keys(self.ssrc2stats[jid].ssrc2bitrate).forEach(
639
                 function (ssrc) {
641
                 function (ssrc) {
640
                     bitrateDownload +=
642
                     bitrateDownload +=
641
-                        self.jid2stats[jid].ssrc2bitrate[ssrc].download;
643
+                        self.ssrc2stats[jid].ssrc2bitrate[ssrc].download;
642
                     bitrateUpload +=
644
                     bitrateUpload +=
643
-                        self.jid2stats[jid].ssrc2bitrate[ssrc].upload;
645
+                        self.ssrc2stats[jid].ssrc2bitrate[ssrc].upload;
644
 
646
 
645
-                    delete self.jid2stats[jid].ssrc2bitrate[ssrc];
647
+                    delete self.ssrc2stats[jid].ssrc2bitrate[ssrc];
646
                 }
648
                 }
647
             );
649
             );
648
-            resolutions[jid] = self.jid2stats[jid].ssrc2resolution;
650
+            resolutions[jid] = self.ssrc2stats[jid].ssrc2resolution;
649
         }
651
         }
650
     );
652
     );
651
 
653
 
652
-    PeerStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload};
654
+    this.conferenceStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload};
653
 
655
 
654
-    PeerStats.packetLoss = {
656
+    this.conferenceStats.packetLoss = {
655
         total:
657
         total:
656
             calculatePacketLoss(lostPackets.download + lostPackets.upload,
658
             calculatePacketLoss(lostPackets.download + lostPackets.upload,
657
                     totalPackets.download + totalPackets.upload),
659
                     totalPackets.download + totalPackets.upload),
662
     };
664
     };
663
     this.eventEmitter.emit("statistics.connectionstats",
665
     this.eventEmitter.emit("statistics.connectionstats",
664
         {
666
         {
665
-            "bitrate": PeerStats.bitrate,
666
-            "packetLoss": PeerStats.packetLoss,
667
-            "bandwidth": PeerStats.bandwidth,
667
+            "bitrate": this.conferenceStats.bitrate,
668
+            "packetLoss": this.conferenceStats.packetLoss,
669
+            "bandwidth": this.conferenceStats.bandwidth,
668
             "resolution": resolutions,
670
             "resolution": resolutions,
669
-            "transport": PeerStats.transport
671
+            "transport": this.conferenceStats.transport
670
         });
672
         });
671
-    PeerStats.transport = [];
673
+    this.conferenceStats.transport = [];
672
 
674
 
673
 };
675
 };
674
 
676
 
683
     for (var idx in this.currentAudioLevelsReport) {
685
     for (var idx in this.currentAudioLevelsReport) {
684
         var now = this.currentAudioLevelsReport[idx];
686
         var now = this.currentAudioLevelsReport[idx];
685
 
687
 
686
-        if (now.type != 'ssrc') {
688
+        //if we don't have "packetsReceived" this is local stream
689
+        if (now.type != 'ssrc' || !getStatValue(now, 'packetsReceived')) {
687
             continue;
690
             continue;
688
         }
691
         }
689
 
692
 
694
         }
697
         }
695
 
698
 
696
         var ssrc = getStatValue(now, 'ssrc');
699
         var ssrc = getStatValue(now, 'ssrc');
697
-        var jid = APP.xmpp.getJidFromSSRC(ssrc);
698
-        if (!jid) {
700
+        if (!ssrc) {
699
             if((Date.now() - now.timestamp) < 3000)
701
             if((Date.now() - now.timestamp) < 3000)
700
-                console.warn("No jid for ssrc: " + ssrc);
702
+                console.warn("No ssrc: ");
701
             continue;
703
             continue;
702
         }
704
         }
703
 
705
 
704
-        var jidStats = this.jid2stats[jid];
705
-        if (!jidStats) {
706
-            jidStats = new PeerStats();
707
-            this.jid2stats[jid] = jidStats;
706
+        var ssrcStats = this.ssrc2stats[ssrc];
707
+        if (!ssrcStats) {
708
+            ssrcStats = new PeerStats();
709
+            this.ssrc2stats[ssrc] = ssrcStats;
708
         }
710
         }
709
 
711
 
710
         // Audio level
712
         // Audio level
725
             // TODO: can't find specs about what this value really is,
727
             // TODO: can't find specs about what this value really is,
726
             // but it seems to vary between 0 and around 32k.
728
             // but it seems to vary between 0 and around 32k.
727
             audioLevel = audioLevel / 32767;
729
             audioLevel = audioLevel / 32767;
728
-            jidStats.setSsrcAudioLevel(ssrc, audioLevel);
729
-            if(jid != APP.xmpp.myJid())
730
-                this.eventEmitter.emit("statistics.audioLevel", jid, audioLevel);
730
+            ssrcStats.setSsrcAudioLevel(ssrc, audioLevel);
731
+            this.eventEmitter.emit("statistics.audioLevel", ssrc, audioLevel);
731
         }
732
         }
732
     }
733
     }
733
 };
734
 };

+ 124
- 121
modules/statistics/statistics.js 查看文件

1
 /* global require, APP */
1
 /* global require, APP */
2
-/**
3
- * Created by hristo on 8/4/14.
4
- */
5
 var LocalStats = require("./LocalStatsCollector.js");
2
 var LocalStats = require("./LocalStatsCollector.js");
6
 var RTPStats = require("./RTPStatsCollector.js");
3
 var RTPStats = require("./RTPStatsCollector.js");
7
 var EventEmitter = require("events");
4
 var EventEmitter = require("events");
8
-var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
9
-var XMPPEvents = require("../../service/xmpp/XMPPEvents");
10
-var CallStats = require("./CallStats");
11
-var RTCEvents = require("../../service/RTC/RTCEvents");
12
-
13
-var eventEmitter = new EventEmitter();
14
-
15
-var localStats = null;
16
-
17
-var rtpStats = null;
18
-
19
-function stopLocal() {
20
-    if (localStats) {
21
-        localStats.stop();
22
-        localStats = null;
23
-    }
5
+//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
6
+//var XMPPEvents = require("../../service/xmpp/XMPPEvents");
7
+//var CallStats = require("./CallStats");
8
+//var RTCEvents = require("../../service/RTC/RTCEvents");
9
+
10
+//
11
+//function onDisposeConference(onUnload) {
12
+//    CallStats.sendTerminateEvent();
13
+//    stopRemote();
14
+//    if(onUnload) {
15
+//        stopLocal();
16
+//        eventEmitter.removeAllListeners();
17
+//    }
18
+//}
19
+
20
+function Statistics() {
21
+    this.localStats = null;
22
+    this.rtpStats = null;
23
+    this.eventEmitter = new EventEmitter();
24
 }
24
 }
25
 
25
 
26
-function stopRemote() {
27
-    if (rtpStats) {
28
-        rtpStats.stop();
29
-        eventEmitter.emit("statistics.stop");
30
-        rtpStats = null;
31
-    }
32
-}
33
-
34
-function startRemoteStats (peerconnection) {
35
-    if (rtpStats) {
36
-        rtpStats.stop();
26
+Statistics.prototype.startRemoteStats = function (peerconnection) {
27
+    if (this.rtpStats) {
28
+        this.rtpStats.stop();
37
     }
29
     }
38
 
30
 
39
-    rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter);
40
-    rtpStats.start();
31
+    this.rtpStats = new RTPStats(peerconnection, 200, 2000, this.eventEmitter);
32
+    this.rtpStats.start();
41
 }
33
 }
42
 
34
 
43
-function onStreamCreated(stream) {
44
-    if(stream.getOriginalStream().getAudioTracks().length === 0) {
35
+Statistics.prototype.startLocalStats = function (stream) {
36
+    if(stream.getType() !== "audio")
45
         return;
37
         return;
46
-    }
47
-
48
-    localStats = new LocalStats(stream.getOriginalStream(), 200, statistics,
49
-        eventEmitter);
50
-    localStats.start();
51
-}
52
-
53
-function onDisposeConference(onUnload) {
54
-    CallStats.sendTerminateEvent();
55
-    stopRemote();
56
-    if(onUnload) {
57
-        stopLocal();
58
-        eventEmitter.removeAllListeners();
59
-    }
38
+    this.localStats = new LocalStats(stream.getOriginalStream(), 200, this,
39
+        this.eventEmitter);
40
+    this.localStats.start();
60
 }
41
 }
61
 
42
 
62
-var statistics = {
63
-    /**
64
-     * Indicates that this audio level is for local jid.
65
-     * @type {string}
66
-     */
67
-    LOCAL_JID: 'local',
68
-
69
-    addAudioLevelListener: function(listener)
70
-    {
71
-        eventEmitter.on("statistics.audioLevel", listener);
72
-    },
73
-
74
-    removeAudioLevelListener: function(listener)
75
-    {
76
-        eventEmitter.removeListener("statistics.audioLevel", listener);
77
-    },
78
-
79
-    addConnectionStatsListener: function(listener)
80
-    {
81
-        eventEmitter.on("statistics.connectionstats", listener);
82
-    },
83
-
84
-    removeConnectionStatsListener: function(listener)
85
-    {
86
-        eventEmitter.removeListener("statistics.connectionstats", listener);
87
-    },
88
 
43
 
44
+Statistics.prototype.addAudioLevelListener = function(listener)
45
+{
46
+    this.eventEmitter.on("statistics.audioLevel", listener);
47
+}
89
 
48
 
90
-    addRemoteStatsStopListener: function(listener)
91
-    {
92
-        eventEmitter.on("statistics.stop", listener);
93
-    },
49
+Statistics.prototype.removeAudioLevelListener = function(listener)
50
+{
51
+    this.eventEmitter.removeListener("statistics.audioLevel", listener);
52
+}
94
 
53
 
95
-    removeRemoteStatsStopListener: function(listener)
96
-    {
97
-        eventEmitter.removeListener("statistics.stop", listener);
98
-    },
99
-
100
-    stop: function () {
101
-        stopLocal();
102
-        stopRemote();
103
-        if(eventEmitter)
104
-        {
105
-            eventEmitter.removeAllListeners();
106
-        }
107
-    },
108
-
109
-    stopRemoteStatistics: function()
54
+Statistics.prototype.dispose = function () {
55
+    this.stopLocal();
56
+    this.stopRemote();
57
+    if(this.eventEmitter)
110
     {
58
     {
111
-        stopRemote();
112
-    },
113
-
114
-    start: function () {
115
-        APP.RTC.addStreamListener(onStreamCreated,
116
-            StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
117
-        APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
118
-        //FIXME: we may want to change CALL INCOMING event to onnegotiationneeded
119
-        APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
120
-            startRemoteStats(event.peerconnection);
121
-//            CallStats.init(event);
122
-        });
123
-        APP.xmpp.addListener(XMPPEvents.PEERCONNECTION_READY, function (session) {
124
-            CallStats.init(session);
125
-        });
126
-        //FIXME: that event is changed to TRACK_MUTE_CHANGED
127
-//        APP.RTC.addListener(RTCEvents.AUDIO_MUTE, function (mute) {
128
-//            CallStats.sendMuteEvent(mute, "audio");
129
-//        });
130
-        APP.xmpp.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function () {
131
-            CallStats.sendSetupFailedEvent();
132
-        });
133
-        //FIXME: that event is changed to TRACK_MUTE_CHANGED
134
-//        APP.RTC.addListener(RTCEvents.VIDEO_MUTE, function (mute) {
135
-//            CallStats.sendMuteEvent(mute, "video");
136
-//        });
59
+        this.eventEmitter.removeAllListeners();
137
     }
60
     }
138
-};
61
+}
139
 
62
 
140
 
63
 
64
+Statistics.prototype.stopLocal = function () {
65
+    if (this.localStats) {
66
+        this.localStats.stop();
67
+        this.localStats = null;
68
+    }
69
+}
141
 
70
 
71
+Statistics.prototype.stopRemote = function () {
72
+    if (this.rtpStats) {
73
+        this.rtpStats.stop();
74
+        this.eventEmitter.emit("statistics.stop");
75
+        this.rtpStats = null;
76
+    }
77
+}
142
 
78
 
143
-module.exports = statistics;
79
+Statistics.LOCAL_JID = require("../../service/statistics/constants").LOCAL_JID;
80
+
81
+//
82
+//var statistics = {
83
+//    /**
84
+//     * Indicates that this audio level is for local jid.
85
+//     * @type {string}
86
+//     */
87
+//    LOCAL_JID: 'local',
88
+//
89
+//    addConnectionStatsListener: function(listener)
90
+//    {
91
+//        eventEmitter.on("statistics.connectionstats", listener);
92
+//    },
93
+//
94
+//    removeConnectionStatsListener: function(listener)
95
+//    {
96
+//        eventEmitter.removeListener("statistics.connectionstats", listener);
97
+//    },
98
+//
99
+//
100
+//    addRemoteStatsStopListener: function(listener)
101
+//    {
102
+//        eventEmitter.on("statistics.stop", listener);
103
+//    },
104
+//
105
+//    removeRemoteStatsStopListener: function(listener)
106
+//    {
107
+//        eventEmitter.removeListener("statistics.stop", listener);
108
+//    },
109
+//
110
+//
111
+//    stopRemoteStatistics: function()
112
+//    {
113
+//        stopRemote();
114
+//    },
115
+//
116
+////    Already implemented with the constructor
117
+//    start: function () {
118
+//        APP.RTC.addStreamListener(onStreamCreated,
119
+//            StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
120
+//        APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
121
+//        //FIXME: we may want to change CALL INCOMING event to onnegotiationneeded
122
+//        APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
123
+//            startRemoteStats(event.peerconnection);
124
+////            CallStats.init(event);
125
+//        });
126
+////        APP.xmpp.addListener(XMPPEvents.PEERCONNECTION_READY, function (session) {
127
+////            CallStats.init(session);
128
+////        });
129
+//        //FIXME: that event is changed to TRACK_MUTE_CHANGED
130
+////        APP.RTC.addListener(RTCEvents.AUDIO_MUTE, function (mute) {
131
+////            CallStats.sendMuteEvent(mute, "audio");
132
+////        });
133
+////        APP.xmpp.addListener(XMPPEvents.CONFERENCE_SETUP_FAILED, function () {
134
+////            CallStats.sendSetupFailedEvent();
135
+////        });
136
+//        //FIXME: that event is changed to TRACK_MUTE_CHANGED
137
+////        APP.RTC.addListener(RTCEvents.VIDEO_MUTE, function (mute) {
138
+////            CallStats.sendMuteEvent(mute, "video");
139
+////        });
140
+//    }
141
+//};
142
+
143
+
144
+
145
+
146
+module.exports = Statistics;

+ 6
- 0
modules/xmpp/ChatRoom.js 查看文件

607
     this.session.addLocalStreams(localStreams);
607
     this.session.addLocalStreams(localStreams);
608
 }
608
 }
609
 
609
 
610
+ChatRoom.prototype.getJidBySSRC = function (ssrc) {
611
+    if (!this.session)
612
+        return null;
613
+    return this.session.getSsrcOwner(ssrc);
614
+};
615
+
610
 module.exports = ChatRoom;
616
 module.exports = ChatRoom;

+ 0
- 7
modules/xmpp/xmpp.js 查看文件

267
     this.connection.moderate.eject(jid);
267
     this.connection.moderate.eject(jid);
268
 };
268
 };
269
 
269
 
270
-XMPP.prototype.getJidFromSSRC = function (ssrc) {
271
-    if (!this.isConferenceInProgress())
272
-        return null;
273
-    return this.connection.jingle.activecall.getSsrcOwner(ssrc);
274
-};
275
-
276
 XMPP.prototype.getSessions = function () {
270
 XMPP.prototype.getSessions = function () {
277
     return this.connection.jingle.sessions;
271
     return this.connection.jingle.sessions;
278
 };
272
 };
279
 
273
 
280
-
281
 XMPP.prototype.disconnect = function () {
274
 XMPP.prototype.disconnect = function () {
282
     if (this.disconnectInProgress || !this.connection || !this.connection.connected)
275
     if (this.disconnectInProgress || !this.connection || !this.connection.connected)
283
     {
276
     {

+ 4
- 0
service/statistics/constants.js 查看文件

1
+var Constants = {
2
+    LOCAL_JID: 'local'
3
+};
4
+module.exports = Constants;

正在加载...
取消
保存