Kaynağa Gözat

Merge branch 'master' into reloads

dev1
hristoterezov 9 yıl önce
ebeveyn
işleme
a1d8f99560

+ 37
- 8
JitsiConference.js Dosyayı Görüntüle

364
     this.room.addListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
364
     this.room.addListener(XMPPEvents.SENDRECV_STREAMS_CHANGED,
365
         track.ssrcHandler);
365
         track.ssrcHandler);
366
 
366
 
367
+    // Report active device to statistics
368
+    var devices = RTC.getCurrentlyAvailableMediaDevices();
369
+    device = devices.find(function (d) {
370
+        return d.kind === track.getTrack().kind + 'input'
371
+            && d.label === track.getTrack().label;
372
+    });
373
+
374
+    Statistics.sendАctiveDeviceListEvent(
375
+        RTC.getEventDataForActiveDevice(device));
376
+
367
     return new Promise(function (resolve, reject) {
377
     return new Promise(function (resolve, reject) {
368
         this.room.addStream(track.getOriginalStream(), function () {
378
         this.room.addStream(track.getOriginalStream(), function () {
369
             if (track.isVideoTrack()) {
379
             if (track.isVideoTrack()) {
1003
     return this.room.connectionTimes;
1013
     return this.room.connectionTimes;
1004
 };
1014
 };
1005
 
1015
 
1016
+/**
1017
+ * Sets a property for the local participant.
1018
+ */
1019
+JitsiConference.prototype.setLocalParticipantProperty = function(name, value) {
1020
+    this.sendCommand("jitsi_participant_" + name, {value: value});
1021
+};
1022
+
1006
 /**
1023
 /**
1007
  * Sends the given feedback through CallStats if enabled.
1024
  * Sends the given feedback through CallStats if enabled.
1008
  *
1025
  *
1148
     conference.room.addListener(XMPPEvents.FOCUS_LEFT, function () {
1165
     conference.room.addListener(XMPPEvents.FOCUS_LEFT, function () {
1149
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.FOCUS_LEFT);
1166
         conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_FAILED, JitsiConferenceErrors.FOCUS_LEFT);
1150
     });
1167
     });
1168
+    conference.room.setParticipantPropertyListener(function (node, from) {
1169
+        var participant = conference.getParticipantById(from);
1170
+        if (!participant) {
1171
+            return;
1172
+        }
1173
+
1174
+        participant.setProperty(
1175
+            node.tagName.substring("jitsi_participant_".length),
1176
+            node.value);
1177
+    });
1151
 //    FIXME
1178
 //    FIXME
1152
 //    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
1179
 //    conference.room.addListener(XMPPEvents.MUC_JOINED, function () {
1153
 //        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
1180
 //        conference.eventEmitter.emit(JitsiConferenceEvents.CONFERENCE_LEFT);
1164
 
1191
 
1165
     conference.room.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, function (role) {
1192
     conference.room.addListener(XMPPEvents.LOCAL_ROLE_CHANGED, function (role) {
1166
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, conference.myUserId(), role);
1193
         conference.eventEmitter.emit(JitsiConferenceEvents.USER_ROLE_CHANGED, conference.myUserId(), role);
1194
+
1195
+        // log all events for the recorder operated by the moderator
1196
+        if (conference.statistics && conference.isModerator()) {
1197
+            conference.on(JitsiConferenceEvents.RECORDER_STATE_CHANGED,
1198
+                function (status, error) {
1199
+                    Statistics.sendLog(
1200
+                        "[Recorder] status: " + status
1201
+                            + (error? " error: " + error : ""));
1202
+                });
1203
+        }
1167
     });
1204
     });
1168
     conference.room.addListener(XMPPEvents.MUC_ROLE_CHANGED, conference.onUserRoleChanged.bind(conference));
1205
     conference.room.addListener(XMPPEvents.MUC_ROLE_CHANGED, conference.onUserRoleChanged.bind(conference));
1169
 
1206
 
1421
                 conference.statistics.sendMuteEvent(track.isMuted(), type);
1458
                 conference.statistics.sendMuteEvent(track.isMuted(), type);
1422
             });
1459
             });
1423
 
1460
 
1424
-        // log all events for the recorder operated by the moderator
1425
-        if (conference.isModerator()) {
1426
-            conference.on(JitsiConferenceEvents.RECORDER_STATE_CHANGED,
1427
-                function (status, error) {
1428
-                    conference.statistics.sendLog("Recorder: " + status);
1429
-                });
1430
-        }
1431
-
1432
         conference.room.addListener(XMPPEvents.CREATE_OFFER_FAILED, function (e, pc) {
1461
         conference.room.addListener(XMPPEvents.CREATE_OFFER_FAILED, function (e, pc) {
1433
             conference.statistics.sendCreateOfferFailed(e, pc);
1462
             conference.statistics.sendCreateOfferFailed(e, pc);
1434
         });
1463
         });

+ 6
- 1
JitsiConferenceEvents.js Dosyayı Görüntüle

130
     /**
130
     /**
131
      * Indicates that authentication status changed.
131
      * Indicates that authentication status changed.
132
      */
132
      */
133
-    AUTH_STATUS_CHANGED: "conference.auth_status_changed"
133
+    AUTH_STATUS_CHANGED: "conference.auth_status_changed",
134
+    /**
135
+     * Indicates that a the value of a specific property of a specific
136
+     * participant has changed.
137
+     */
138
+    PARTICIPANT_PROPERTY_CHANGED: "conference.participant_property_changed"
134
 };
139
 };
135
 
140
 
136
 module.exports = JitsiConferenceEvents;
141
 module.exports = JitsiConferenceEvents;

+ 39
- 0
JitsiMediaDevices.js Dosyayı Görüntüle

3
 var RTC = require("./modules/RTC/RTC");
3
 var RTC = require("./modules/RTC/RTC");
4
 var MediaType = require('./service/RTC/MediaType');
4
 var MediaType = require('./service/RTC/MediaType');
5
 var JitsiMediaDevicesEvents = require('./JitsiMediaDevicesEvents');
5
 var JitsiMediaDevicesEvents = require('./JitsiMediaDevicesEvents');
6
+var Statistics = require("./modules/statistics/statistics");
6
 
7
 
7
 var eventEmitter = new EventEmitter();
8
 var eventEmitter = new EventEmitter();
8
 
9
 
11
         eventEmitter.emit(JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED, devices);
12
         eventEmitter.emit(JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED, devices);
12
     });
13
     });
13
 
14
 
15
+RTC.addListener(RTCEvents.DEVICE_LIST_AVAILABLE,
16
+    function (devices) {
17
+        // log output device
18
+        logOutputDevice(
19
+            JitsiMediaDevices.getAudioOutputDevice(),
20
+            devices);
21
+    });
22
+
23
+/**
24
+ * Gathers data and sends it to statistics.
25
+ * @param deviceID the device id to log
26
+ * @param devices list of devices
27
+ */
28
+function logOutputDevice (deviceID, devices) {
29
+    var device = devices.find(function (d) {
30
+        return d.kind === 'audiooutput' && d.deviceId === deviceID;
31
+    });
32
+
33
+    Statistics.sendАctiveDeviceListEvent(
34
+        RTC.getEventDataForActiveDevice(device));
35
+}
36
+
14
 var JitsiMediaDevices = {
37
 var JitsiMediaDevices = {
15
     /**
38
     /**
16
      * Executes callback with list of media devices connected.
39
      * Executes callback with list of media devices connected.
71
      *      otherwise
94
      *      otherwise
72
      */
95
      */
73
     setAudioOutputDevice: function (deviceId) {
96
     setAudioOutputDevice: function (deviceId) {
97
+
98
+        if (RTC.getCurrentlyAvailableMediaDevices().length > 0)
99
+        {
100
+            // if we have devices info report device to stats
101
+            // normally this will not happen on startup as this method is called
102
+            // too early. This will happen only on user selection of new device
103
+            logOutputDevice(deviceId, RTC.getCurrentlyAvailableMediaDevices());
104
+        }
105
+
74
         return RTC.setAudioOutputDevice(deviceId);
106
         return RTC.setAudioOutputDevice(deviceId);
75
     },
107
     },
76
     /**
108
     /**
88
      */
120
      */
89
     removeEventListener: function (event, handler) {
121
     removeEventListener: function (event, handler) {
90
         eventEmitter.removeListener(event, handler);
122
         eventEmitter.removeListener(event, handler);
123
+    },
124
+    /**
125
+     * Emits an event.
126
+     * @param {string} event - event name
127
+     */
128
+    emitEvent: function (event) {
129
+        eventEmitter.emit.apply(eventEmitter, arguments);
91
     }
130
     }
92
 };
131
 };
93
 
132
 

+ 11
- 1
JitsiMediaDevicesEvents.js Dosyayı Görüntüle

11
      *  MediaDeviceInfo-like objects that are currently connected.
11
      *  MediaDeviceInfo-like objects that are currently connected.
12
      *  @see https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo
12
      *  @see https://developer.mozilla.org/en-US/docs/Web/API/MediaDeviceInfo
13
      */
13
      */
14
-    DEVICE_LIST_CHANGED: "mediaDevices.devicechange"
14
+    DEVICE_LIST_CHANGED: "mediaDevices.devicechange",
15
+    /**
16
+     * Indicates that the environment is currently showing permission prompt to
17
+     * access camera and/or microphone. The event provides the following
18
+     * parameters to its listeners:
19
+     *
20
+     * @param {'chrome'|'opera'|'firefox'|'iexplorer'|'safari'|'nwjs'
21
+     *      |'react-native'|'android'} environmentType - type of browser or
22
+     *      other execution environment.
23
+     */
24
+    PERMISSION_PROMPT_IS_SHOWN: "mediaDevices.permissionPromptIsShown"
15
 };
25
 };
16
 
26
 
17
 module.exports = JitsiMediaDevicesEvents;
27
 module.exports = JitsiMediaDevicesEvents;

+ 34
- 3
JitsiMeetJS.js Dosyayı Görüntüle

18
 var Resolutions = require("./service/RTC/Resolutions");
18
 var Resolutions = require("./service/RTC/Resolutions");
19
 var ScriptUtil = require("./modules/util/ScriptUtil");
19
 var ScriptUtil = require("./modules/util/ScriptUtil");
20
 var GlobalOnErrorHandler = require("./modules/util/GlobalOnErrorHandler");
20
 var GlobalOnErrorHandler = require("./modules/util/GlobalOnErrorHandler");
21
+var RTCBrowserType = require("./modules/RTC/RTCBrowserType");
22
+
23
+// The amount of time to wait until firing
24
+// JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN event
25
+var USER_MEDIA_PERMISSION_PROMPT_TIMEOUT = 500;
21
 
26
 
22
 function getLowerResolution(resolution) {
27
 function getLowerResolution(resolution) {
23
     if(!Resolutions[resolution])
28
     if(!Resolutions[resolution])
103
      * will be returned trough the Promise, otherwise JitsiTrack objects will be returned.
108
      * will be returned trough the Promise, otherwise JitsiTrack objects will be returned.
104
      * @param {string} options.cameraDeviceId
109
      * @param {string} options.cameraDeviceId
105
      * @param {string} options.micDeviceId
110
      * @param {string} options.micDeviceId
111
+     * @param {boolean} (firePermissionPromptIsShownEvent) - if event
112
+     *      JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN should be fired
106
      * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>}
113
      * @returns {Promise.<{Array.<JitsiTrack>}, JitsiConferenceError>}
107
      *     A promise that returns an array of created JitsiTracks if resolved,
114
      *     A promise that returns an array of created JitsiTracks if resolved,
108
      *     or a JitsiConferenceError if rejected.
115
      *     or a JitsiConferenceError if rejected.
109
      */
116
      */
110
-    createLocalTracks: function (options) {
111
-        return RTC.obtainAudioAndVideoPermissions(options || {}).then(
112
-            function(tracks) {
117
+    createLocalTracks: function (options, firePermissionPromptIsShownEvent) {
118
+        var promiseFulfilled = false;
119
+
120
+        if (firePermissionPromptIsShownEvent === true) {
121
+            window.setTimeout(function () {
122
+                if (!promiseFulfilled) {
123
+                    var browser = RTCBrowserType.getBrowserType()
124
+                        .split('rtc_browser.')[1];
125
+
126
+                    if (RTCBrowserType.isAndroid()) {
127
+                        browser = 'android';
128
+                    }
129
+
130
+                    JitsiMediaDevices.emitEvent(
131
+                        JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN,
132
+                        browser);
133
+                }
134
+            }, USER_MEDIA_PERMISSION_PROMPT_TIMEOUT);
135
+        }
136
+
137
+        return RTC.obtainAudioAndVideoPermissions(options || {})
138
+            .then(function(tracks) {
139
+                promiseFulfilled = true;
140
+
113
                 if(!RTC.options.disableAudioLevels)
141
                 if(!RTC.options.disableAudioLevels)
114
                     for(var i = 0; i < tracks.length; i++) {
142
                     for(var i = 0; i < tracks.length; i++) {
115
                         var track = tracks[i];
143
                         var track = tracks[i];
124
                                 });
152
                                 });
125
                         }
153
                         }
126
                     }
154
                     }
155
+
127
                 return tracks;
156
                 return tracks;
128
             }).catch(function (error) {
157
             }).catch(function (error) {
158
+                promiseFulfilled = true;
159
+
129
                 Statistics.sendGetUserMediaFailed(error);
160
                 Statistics.sendGetUserMediaFailed(error);
130
 
161
 
131
                 if(error.name === JitsiTrackErrors.UNSUPPORTED_RESOLUTION) {
162
                 if(error.name === JitsiTrackErrors.UNSUPPORTED_RESOLUTION) {

+ 29
- 0
JitsiParticipant.js Dosyayı Görüntüle

1
 /* global Strophe */
1
 /* global Strophe */
2
+var JitsiConferenceEvents = require('./JitsiConferenceEvents');
2
 
3
 
3
 /**
4
 /**
4
  * Represents a participant in (a member of) a conference.
5
  * Represents a participant in (a member of) a conference.
21
         video: undefined
22
         video: undefined
22
     };
23
     };
23
     this._isHidden = isHidden;
24
     this._isHidden = isHidden;
25
+    this._properties = {};
24
 }
26
 }
25
 
27
 
26
 /**
28
 /**
30
     return this._conference;
32
     return this._conference;
31
 };
33
 };
32
 
34
 
35
+/**
36
+ * Gets the value of a property of this participant.
37
+ */
38
+JitsiParticipant.prototype.getProperty = function(name) {
39
+    return this._properties[name];
40
+};
41
+
42
+/**
43
+ * Sets the value of a property of this participant, and fires an event if the
44
+ * value has changed.
45
+ * @name the name of the property.
46
+ * @value the value to set.
47
+ */
48
+JitsiParticipant.prototype.setProperty = function(name, value) {
49
+    var oldValue = this._properties[name];
50
+    this._properties[name] = value;
51
+
52
+    if (value !== oldValue) {
53
+        this._conference.eventEmitter.emit(
54
+            JitsiConferenceEvents.PARTICIPANT_PROPERTY_CHANGED,
55
+            this,
56
+            name,
57
+            oldValue,
58
+            value);
59
+    }
60
+};
61
+
33
 /**
62
 /**
34
  * @returns {Array.<JitsiTrack>} The list of media tracks for this participant.
63
  * @returns {Array.<JitsiTrack>} The list of media tracks for this participant.
35
  */
64
  */

+ 3
- 2
doc/API.md Dosyayı Görüntüle

58
 JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
58
 JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);
59
 ```
59
 ```
60
 
60
 
61
-* ```JitsiMeetJS.createLocalTracks(options)``` - Creates the media tracks and returns them trough ```Promise``` object. If rejected, passes ```JitsiTrackError``` instance to catch block.
61
+* ```JitsiMeetJS.createLocalTracks(options, firePermissionPromptIsShownEvent)``` - Creates the media tracks and returns them trough ```Promise``` object. If rejected, passes ```JitsiTrackError``` instance to catch block.
62
     - options - JS object with configuration options for the local media tracks. You can change the following properties there:
62
     - options - JS object with configuration options for the local media tracks. You can change the following properties there:
63
         1. devices - array with the devices - "desktop", "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices.
63
         1. devices - array with the devices - "desktop", "video" and "audio" that will be passed to GUM. If that property is not set GUM will try to get all available devices.
64
         2. resolution - the prefered resolution for the local video.
64
         2. resolution - the prefered resolution for the local video.
67
         5. minFps - the minimum frame rate for the video stream (passed to GUM)
67
         5. minFps - the minimum frame rate for the video stream (passed to GUM)
68
         6. maxFps - the maximum frame rate for the video stream (passed to GUM)
68
         6. maxFps - the maximum frame rate for the video stream (passed to GUM)
69
         7. facingMode - facing mode for a camera (possible values - 'user', 'environment')
69
         7. facingMode - facing mode for a camera (possible values - 'user', 'environment')
70
+    - firePermissionPromptIsShownEvent - optional boolean parameter. If set to ```true```, ```JitsiMediaDevicesEvents.PERMISSION_PROMPT_IS_SHOWN``` will be fired when browser shows gUM permission prompt.
70
 
71
 
71
 * ```JitsiMeetJS.enumerateDevices(callback)``` - __DEPRECATED__. Use ```JitsiMeetJS.mediaDevices.enumerateDevices(callback)``` instead.
72
 * ```JitsiMeetJS.enumerateDevices(callback)``` - __DEPRECATED__. Use ```JitsiMeetJS.mediaDevices.enumerateDevices(callback)``` instead.
72
 * ```JitsiMeetJS.isDeviceListAvailable()``` - __DEPRECATED__. Use ```JitsiMeetJS.mediaDevices.isDeviceListAvailable()``` instead.
73
 * ```JitsiMeetJS.isDeviceListAvailable()``` - __DEPRECATED__. Use ```JitsiMeetJS.mediaDevices.isDeviceListAvailable()``` instead.
88
     - ```addEventListener(event, handler)``` - attaches an event handler.
89
     - ```addEventListener(event, handler)``` - attaches an event handler.
89
     - ```removeEventListener(event, handler)``` - removes an event handler.
90
     - ```removeEventListener(event, handler)``` - removes an event handler.
90
 
91
 
91
-
92
 * ```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.
92
 * ```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.
93
     We have two event types - connection and conference. You can access the events with the following code ```JitsiMeetJS.events.<event_type>.<event_name>```.
93
     We have two event types - connection and conference. You can access the events with the following code ```JitsiMeetJS.events.<event_type>.<event_name>```.
94
     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```.
94
     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```.
132
 
132
 
133
     4. mediaDevices
133
     4. mediaDevices
134
         - DEVICE_LIST_CHANGED - indicates that list of currently connected devices has changed (parameters - devices(MediaDeviceInfo[])).
134
         - DEVICE_LIST_CHANGED - indicates that list of currently connected devices has changed (parameters - devices(MediaDeviceInfo[])).
135
+        - PERMISSION_PROMPT_IS_SHOWN - Indicates that the environment is currently showing permission prompt to access camera and/or microphone (parameters - environmentType ('chrome'|'opera'|'firefox'|'iexplorer'|'safari'|'nwjs'|'react-native'|'android').
135
 
136
 
136
 
137
 
137
 * ```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
138
 * ```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

+ 17
- 0
modules/RTC/RTC.js Dosyayı Görüntüle

299
     return RTCUtils.getAudioOutputDevice();
299
     return RTCUtils.getAudioOutputDevice();
300
 };
300
 };
301
 
301
 
302
+/**
303
+ * Returns list of available media devices if its obtained, otherwise an
304
+ * empty array is returned/
305
+ * @returns {Array} list of available media devices.
306
+ */
307
+RTC.getCurrentlyAvailableMediaDevices = function () {
308
+    return RTCUtils.getCurrentlyAvailableMediaDevices();
309
+};
310
+
311
+/**
312
+ * Returns event data for device to be reported to stats.
313
+ * @returns {MediaDeviceInfo} device.
314
+ */
315
+RTC.getEventDataForActiveDevice = function (device) {
316
+    return RTCUtils.getEventDataForActiveDevice(device);
317
+};
318
+
302
 /**
319
 /**
303
  * Sets current audio output device.
320
  * Sets current audio output device.
304
  * @param {string} deviceId - id of 'audiooutput' device from
321
  * @param {string} deviceId - id of 'audiooutput' device from

+ 50
- 0
modules/RTC/RTCBrowserType.js Dosyayı Görüntüle

22
 
22
 
23
     RTC_BROWSER_REACT_NATIVE: "rtc_browser.react-native",
23
     RTC_BROWSER_REACT_NATIVE: "rtc_browser.react-native",
24
 
24
 
25
+    /**
26
+     * Gets current browser type.
27
+     * @returns {string}
28
+     */
25
     getBrowserType: function () {
29
     getBrowserType: function () {
26
         return currentBrowser;
30
         return currentBrowser;
27
     },
31
     },
28
 
32
 
33
+    /**
34
+     * Checks if current browser is Chrome.
35
+     * @returns {boolean}
36
+     */
29
     isChrome: function () {
37
     isChrome: function () {
30
         return currentBrowser === RTCBrowserType.RTC_BROWSER_CHROME;
38
         return currentBrowser === RTCBrowserType.RTC_BROWSER_CHROME;
31
     },
39
     },
32
 
40
 
41
+    /**
42
+     * Checks if current browser is Opera.
43
+     * @returns {boolean}
44
+     */
33
     isOpera: function () {
45
     isOpera: function () {
34
         return currentBrowser === RTCBrowserType.RTC_BROWSER_OPERA;
46
         return currentBrowser === RTCBrowserType.RTC_BROWSER_OPERA;
35
     },
47
     },
48
+
49
+    /**
50
+     * Checks if current browser is Firefox.
51
+     * @returns {boolean}
52
+     */
36
     isFirefox: function () {
53
     isFirefox: function () {
37
         return currentBrowser === RTCBrowserType.RTC_BROWSER_FIREFOX;
54
         return currentBrowser === RTCBrowserType.RTC_BROWSER_FIREFOX;
38
     },
55
     },
39
 
56
 
57
+    /**
58
+     * Checks if current browser is Internet Explorer.
59
+     * @returns {boolean}
60
+     */
40
     isIExplorer: function () {
61
     isIExplorer: function () {
41
         return currentBrowser === RTCBrowserType.RTC_BROWSER_IEXPLORER;
62
         return currentBrowser === RTCBrowserType.RTC_BROWSER_IEXPLORER;
42
     },
63
     },
43
 
64
 
65
+    /**
66
+     * Checks if current browser is Safari.
67
+     * @returns {boolean}
68
+     */
44
     isSafari: function () {
69
     isSafari: function () {
45
         return currentBrowser === RTCBrowserType.RTC_BROWSER_SAFARI;
70
         return currentBrowser === RTCBrowserType.RTC_BROWSER_SAFARI;
46
     },
71
     },
72
+
73
+    /**
74
+     * Checks if current environment is NWJS.
75
+     * @returns {boolean}
76
+     */
47
     isNWJS: function () {
77
     isNWJS: function () {
48
         return currentBrowser === RTCBrowserType.RTC_BROWSER_NWJS;
78
         return currentBrowser === RTCBrowserType.RTC_BROWSER_NWJS;
49
     },
79
     },
80
+
81
+    /**
82
+     * Checks if current environment is React Native.
83
+     * @returns {boolean}
84
+     */
50
     isReactNative: function () {
85
     isReactNative: function () {
51
         return currentBrowser === RTCBrowserType.RTC_BROWSER_REACT_NATIVE;
86
         return currentBrowser === RTCBrowserType.RTC_BROWSER_REACT_NATIVE;
52
     },
87
     },
88
+
89
+    /**
90
+     * Checks if Temasys RTC plugin is used.
91
+     * @returns {boolean}
92
+     */
53
     isTemasysPluginUsed: function () {
93
     isTemasysPluginUsed: function () {
54
         return RTCBrowserType.isIExplorer() || RTCBrowserType.isSafari();
94
         return RTCBrowserType.isIExplorer() || RTCBrowserType.isSafari();
55
     },
95
     },
96
+
97
+    /**
98
+     * Returns Firefox version.
99
+     * @returns {number|null}
100
+     */
56
     getFirefoxVersion: function () {
101
     getFirefoxVersion: function () {
57
         return RTCBrowserType.isFirefox() ? browserVersion : null;
102
         return RTCBrowserType.isFirefox() ? browserVersion : null;
58
     },
103
     },
59
 
104
 
105
+    /**
106
+     * Returns Chrome version.
107
+     * @returns {number|null}
108
+     */
60
     getChromeVersion: function () {
109
     getChromeVersion: function () {
61
         return RTCBrowserType.isChrome() ? browserVersion : null;
110
         return RTCBrowserType.isChrome() ? browserVersion : null;
62
     },
111
     },
72
 
121
 
73
     /**
122
     /**
74
      * Whether the browser is running on an android device.
123
      * Whether the browser is running on an android device.
124
+     * @returns {boolean}
75
      */
125
      */
76
     isAndroid: function() {
126
     isAndroid: function() {
77
         return isAndroid;
127
         return isAndroid;

+ 48
- 7
modules/RTC/RTCUtils.js Dosyayı Görüntüle

40
 var isAudioOutputDeviceChangeAvailable =
40
 var isAudioOutputDeviceChangeAvailable =
41
     typeof featureDetectionAudioEl.setSinkId !== 'undefined';
41
     typeof featureDetectionAudioEl.setSinkId !== 'undefined';
42
 
42
 
43
-var currentlyAvailableMediaDevices = [];
43
+var currentlyAvailableMediaDevices;
44
 
44
 
45
 var rawEnumerateDevicesWithCallback = navigator.mediaDevices
45
 var rawEnumerateDevicesWithCallback = navigator.mediaDevices
46
     && navigator.mediaDevices.enumerateDevices
46
     && navigator.mediaDevices.enumerateDevices
327
     // and then plug in a new one.
327
     // and then plug in a new one.
328
     if (rawEnumerateDevicesWithCallback) {
328
     if (rawEnumerateDevicesWithCallback) {
329
         rawEnumerateDevicesWithCallback(function (devices) {
329
         rawEnumerateDevicesWithCallback(function (devices) {
330
-            if (compareAvailableMediaDevices(devices)) {
330
+            // We don't fire RTCEvents.DEVICE_LIST_CHANGED for the first time
331
+            // we call enumerateDevices(). This is the initial step.
332
+            if (typeof currentlyAvailableMediaDevices === 'undefined') {
333
+                currentlyAvailableMediaDevices = devices.slice(0);
334
+            } else if (compareAvailableMediaDevices(devices)) {
331
                 onMediaDevicesListChanged(devices);
335
                 onMediaDevicesListChanged(devices);
332
             }
336
             }
333
 
337
 
382
     eventEmitter.emit(RTCEvents.RTC_READY, true);
386
     eventEmitter.emit(RTCEvents.RTC_READY, true);
383
     screenObtainer.init(options, GUM);
387
     screenObtainer.init(options, GUM);
384
 
388
 
385
-    if (isDeviceChangeEventSupported && RTCUtils.isDeviceListAvailable()) {
386
-        navigator.mediaDevices.addEventListener('devicechange', function () {
387
-            RTCUtils.enumerateDevices(onMediaDevicesListChanged);
389
+    if (RTCUtils.isDeviceListAvailable() && rawEnumerateDevicesWithCallback) {
390
+        rawEnumerateDevicesWithCallback(function (devices) {
391
+            currentlyAvailableMediaDevices = devices.splice(0);
392
+
393
+            eventEmitter.emit(RTCEvents.DEVICE_LIST_AVAILABLE,
394
+                currentlyAvailableMediaDevices);
395
+
396
+            if (isDeviceChangeEventSupported) {
397
+                navigator.mediaDevices.addEventListener(
398
+                    'devicechange',
399
+                    function () {
400
+                        RTCUtils.enumerateDevices(
401
+                            onMediaDevicesListChanged);
402
+                    });
403
+            } else {
404
+                pollForAvailableMediaDevices();
405
+            }
388
         });
406
         });
389
-    } else if (RTCUtils.isDeviceListAvailable()) {
390
-        pollForAvailableMediaDevices();
391
     }
407
     }
392
 }
408
 }
393
 
409
 
1203
      */
1219
      */
1204
     getAudioOutputDevice: function () {
1220
     getAudioOutputDevice: function () {
1205
         return audioOutputDeviceId;
1221
         return audioOutputDeviceId;
1222
+    },
1223
+
1224
+    /**
1225
+     * Returns list of available media devices if its obtained, otherwise an
1226
+     * empty array is returned/
1227
+     * @returns {Array} list of available media devices.
1228
+     */
1229
+    getCurrentlyAvailableMediaDevices: function () {
1230
+        return currentlyAvailableMediaDevices;
1231
+    },
1232
+
1233
+    /**
1234
+     * Returns event data for device to be reported to stats.
1235
+     * @returns {MediaDeviceInfo} device.
1236
+     */
1237
+    getEventDataForActiveDevice: function (device) {
1238
+        var devices = [];
1239
+        var deviceData = {
1240
+            "deviceId": device.deviceId,
1241
+            "kind":     device.kind,
1242
+            "label":    device.label,
1243
+            "groupId":  device.groupId
1244
+        };
1245
+        devices.push(deviceData);
1246
+        return { deviceList: devices };
1206
     }
1247
     }
1207
 };
1248
 };
1208
 
1249
 

+ 93
- 34
modules/statistics/CallStats.js Dosyayı Görüntüle

20
     getUserMedia:         "getUserMedia",
20
     getUserMedia:         "getUserMedia",
21
     iceConnectionFailure: "iceConnectionFailure",
21
     iceConnectionFailure: "iceConnectionFailure",
22
     signalingError:       "signalingError",
22
     signalingError:       "signalingError",
23
-    applicationError:     "applicationError"
23
+    applicationLog:       "applicationLog"
24
 };
24
 };
25
 
25
 
26
 /**
26
 /**
41
     fabricTerminated:"fabricTerminated",
41
     fabricTerminated:"fabricTerminated",
42
     screenShareStart:"screenShareStart",
42
     screenShareStart:"screenShareStart",
43
     screenShareStop:"screenShareStop",
43
     screenShareStop:"screenShareStop",
44
-    dominantSpeaker:"dominantSpeaker"
44
+    dominantSpeaker:"dominantSpeaker",
45
+    activeDeviceList:"activeDeviceList"
45
 };
46
 };
46
 
47
 
47
 var callStats = null;
48
 var callStats = null;
53
     if (err !== 'success')
54
     if (err !== 'success')
54
         return;
55
         return;
55
 
56
 
57
+    CallStats.initialized = true;
58
+
59
+    var ret = callStats.addNewFabric(this.peerconnection,
60
+        Strophe.getResourceFromJid(this.session.peerjid),
61
+        callStats.fabricUsage.multiplex,
62
+        this.confID,
63
+        this.pcCallback.bind(this));
64
+
65
+    var fabricInitialized = (ret.status === 'success');
66
+
67
+    if(!fabricInitialized)
68
+        console.log("callstats fabric not initilized", ret.message);
69
+
56
     // notify callstats about failures if there were any
70
     // notify callstats about failures if there were any
57
     if (CallStats.reportsQueue.length) {
71
     if (CallStats.reportsQueue.length) {
58
         CallStats.reportsQueue.forEach(function (report) {
72
         CallStats.reportsQueue.forEach(function (report) {
59
-            if (report.type === reportType.ERROR)
60
-            {
73
+            if (report.type === reportType.ERROR) {
61
                 var error = report.data;
74
                 var error = report.data;
62
                 CallStats._reportError.call(this, error.type, error.error,
75
                 CallStats._reportError.call(this, error.type, error.error,
63
                     error.pc);
76
                     error.pc);
64
             }
77
             }
65
-            else if (report.type === reportType.EVENT)
66
-            {
67
-                var data = report.data;
78
+            // if we have and event to report and we failed to add fabric
79
+            // this event will not be reported anyway, returning an error
80
+            else if (report.type === reportType.EVENT
81
+                && fabricInitialized) {
82
+                var eventData = report.data;
68
                 callStats.sendFabricEvent(
83
                 callStats.sendFabricEvent(
69
-                    this.peerconnection, data.event, this.confID);
84
+                    this.peerconnection,
85
+                    eventData.event,
86
+                    this.confID,
87
+                    eventData.eventData);
88
+            } else if (report.type === reportType.MST_WITH_USERID) {
89
+                var data = report.data;
90
+                callStats.associateMstWithUserID(
91
+                    this.peerconnection,
92
+                    data.callStatsId,
93
+                    this.confID,
94
+                    data.ssrc,
95
+                    data.usageLabel,
96
+                    data.containerId
97
+                );
70
             }
98
             }
71
         }, this);
99
         }, this);
72
         CallStats.reportsQueue.length = 0;
100
         CallStats.reportsQueue.length = 0;
123
             this.userID,
151
             this.userID,
124
             initCallback.bind(this));
152
             initCallback.bind(this));
125
 
153
 
126
-        callStats.addNewFabric(this.peerconnection,
127
-            Strophe.getResourceFromJid(jingleSession.peerjid),
128
-            callStats.fabricUsage.multiplex,
129
-            this.confID,
130
-            this.pcCallback.bind(this));
131
     } catch (e) {
154
     } catch (e) {
132
         // The callstats.io API failed to initialize (e.g. because its
155
         // The callstats.io API failed to initialize (e.g. because its
133
         // download failed to succeed in general or on time). Further
156
         // download failed to succeed in general or on time). Further
143
 // and send them to callstats on init
166
 // and send them to callstats on init
144
 CallStats.reportsQueue = [];
167
 CallStats.reportsQueue = [];
145
 
168
 
169
+/**
170
+ * Whether the library was successfully initialized using its initialize method.
171
+ * And whether we had successfully called addNewFabric.
172
+ * @type {boolean}
173
+ */
174
+CallStats.initialized = false;
175
+
146
 /**
176
 /**
147
  * Type of pending reports, can be event or an error.
177
  * Type of pending reports, can be event or an error.
148
  * @type {{ERROR: string, EVENT: string}}
178
  * @type {{ERROR: string, EVENT: string}}
149
  */
179
  */
150
 var reportType = {
180
 var reportType = {
151
     ERROR: "error",
181
     ERROR: "error",
152
-    EVENT: "event"
182
+    EVENT: "event",
183
+    MST_WITH_USERID: "mstWithUserID"
153
 };
184
 };
154
 
185
 
155
 CallStats.prototype.pcCallback = _try_catch(function (err, msg) {
186
 CallStats.prototype.pcCallback = _try_catch(function (err, msg) {
162
 /**
193
 /**
163
  * Lets CallStats module know where is given SSRC rendered by providing renderer
194
  * Lets CallStats module know where is given SSRC rendered by providing renderer
164
  * tag ID.
195
  * tag ID.
196
+ * If the lib is not initialized yet queue the call for later, when its ready.
165
  * @param ssrc {number} the SSRC of the stream
197
  * @param ssrc {number} the SSRC of the stream
166
  * @param isLocal {boolean} <tt>true<tt> if this stream is local or
198
  * @param isLocal {boolean} <tt>true<tt> if this stream is local or
167
  *        <tt>false</tt> otherwise.
199
  *        <tt>false</tt> otherwise.
191
             usageLabel,
223
             usageLabel,
192
             containerId
224
             containerId
193
         );
225
         );
194
-        callStats.associateMstWithUserID(
195
-            this.peerconnection,
196
-            callStatsId,
197
-            this.confID,
198
-            ssrc,
199
-            usageLabel,
200
-            containerId
201
-        );
226
+        if(CallStats.initialized) {
227
+            callStats.associateMstWithUserID(
228
+                this.peerconnection,
229
+                callStatsId,
230
+                this.confID,
231
+                ssrc,
232
+                usageLabel,
233
+                containerId
234
+            );
235
+        }
236
+        else {
237
+            CallStats.reportsQueue.push({
238
+                type: reportType.MST_WITH_USERID,
239
+                data: {
240
+                    callStatsId: callStatsId,
241
+                    ssrc: ssrc,
242
+                    usageLabel: usageLabel,
243
+                    containerId: containerId
244
+                }
245
+            });
246
+        }
202
     }).bind(this)();
247
     }).bind(this)();
203
 };
248
 };
204
 
249
 
206
  * Notifies CallStats for mute events
251
  * Notifies CallStats for mute events
207
  * @param mute {boolean} true for muted and false for not muted
252
  * @param mute {boolean} true for muted and false for not muted
208
  * @param type {String} "audio"/"video"
253
  * @param type {String} "audio"/"video"
254
+ * @param {CallStats} cs callstats instance related to the event
209
  */
255
  */
210
 CallStats.sendMuteEvent = _try_catch(function (mute, type, cs) {
256
 CallStats.sendMuteEvent = _try_catch(function (mute, type, cs) {
211
 
257
 
224
  * Notifies CallStats for screen sharing events
270
  * Notifies CallStats for screen sharing events
225
  * @param start {boolean} true for starting screen sharing and
271
  * @param start {boolean} true for starting screen sharing and
226
  * false for not stopping
272
  * false for not stopping
273
+ * @param {CallStats} cs callstats instance related to the event
227
  */
274
  */
228
 CallStats.sendScreenSharingEvent = _try_catch(function (start, cs) {
275
 CallStats.sendScreenSharingEvent = _try_catch(function (start, cs) {
229
 
276
 
233
 
280
 
234
 /**
281
 /**
235
  * Notifies CallStats that we are the new dominant speaker in the conference.
282
  * Notifies CallStats that we are the new dominant speaker in the conference.
283
+ * @param {CallStats} cs callstats instance related to the event
236
  */
284
  */
237
 CallStats.sendDominantSpeakerEvent = _try_catch(function (cs) {
285
 CallStats.sendDominantSpeakerEvent = _try_catch(function (cs) {
238
 
286
 
240
         fabricEvent.dominantSpeaker);
288
         fabricEvent.dominantSpeaker);
241
 });
289
 });
242
 
290
 
291
+/**
292
+ * Notifies CallStats about active device.
293
+ * @param {{deviceList: {String:String}}} list of devices with their data
294
+ * @param {CallStats} cs callstats instance related to the event
295
+ */
296
+CallStats.sendАctiveDeviceListEvent = _try_catch(function (devicesData, cs) {
297
+
298
+    CallStats._reportEvent.call(cs, fabricEvent.activeDeviceList, devicesData);
299
+});
300
+
243
 /**
301
 /**
244
  * Reports an error to callstats.
302
  * Reports an error to callstats.
245
  *
303
  *
246
  * @param type the type of the error, which will be one of the wrtcFuncNames
304
  * @param type the type of the error, which will be one of the wrtcFuncNames
247
  * @param e the error
305
  * @param e the error
248
  * @param pc the peerconnection
306
  * @param pc the peerconnection
307
+ * @param eventData additional data to pass to event
249
  * @private
308
  * @private
250
  */
309
  */
251
-CallStats._reportEvent = function (event) {
252
-    if (callStats) {
253
-        callStats.sendFabricEvent(this.peerconnection, event, this.confID);
310
+CallStats._reportEvent = function (event, eventData) {
311
+    if (CallStats.initialized) {
312
+        callStats.sendFabricEvent(
313
+            this.peerconnection, event, this.confID, eventData);
254
     } else {
314
     } else {
255
         CallStats.reportsQueue.push({
315
         CallStats.reportsQueue.push({
256
                 type: reportType.EVENT,
316
                 type: reportType.EVENT,
257
-                data: {event: event}
317
+                data: {event: event, eventData: eventData}
258
             });
318
             });
259
     }
319
     }
260
 };
320
 };
263
  * Notifies CallStats for connection setup errors
323
  * Notifies CallStats for connection setup errors
264
  */
324
  */
265
 CallStats.prototype.sendTerminateEvent = _try_catch(function () {
325
 CallStats.prototype.sendTerminateEvent = _try_catch(function () {
266
-    if(!callStats) {
326
+    if(!CallStats.initialized) {
267
         return;
327
         return;
268
     }
328
     }
269
     callStats.sendFabricEvent(this.peerconnection,
329
     callStats.sendFabricEvent(this.peerconnection,
289
  */
349
  */
290
 CallStats.prototype.sendFeedback = _try_catch(
350
 CallStats.prototype.sendFeedback = _try_catch(
291
 function(overallFeedback, detailedFeedback) {
351
 function(overallFeedback, detailedFeedback) {
292
-    if(!callStats) {
352
+    if(!CallStats.initialized) {
293
         return;
353
         return;
294
     }
354
     }
295
     var feedbackString =    '{"userID":"' + this.userID + '"' +
355
     var feedbackString =    '{"userID":"' + this.userID + '"' +
314
         logger.warn("No error is passed!");
374
         logger.warn("No error is passed!");
315
         e = new Error("Unknown error");
375
         e = new Error("Unknown error");
316
     }
376
     }
317
-    if (callStats) {
377
+    if (CallStats.initialized) {
318
         callStats.reportError(pc, this.confID, type, e);
378
         callStats.reportError(pc, this.confID, type, e);
319
     } else {
379
     } else {
320
         CallStats.reportsQueue.push({
380
         CallStats.reportsQueue.push({
391
 });
451
 });
392
 
452
 
393
 /**
453
 /**
394
- * Notifies CallStats that there is an unhandled error on the page.
454
+ * Notifies CallStats that there is a log we want to report.
395
  *
455
  *
396
- * @param {Error} e error to send
397
- * @param {RTCPeerConnection} pc connection on which failure occured.
456
+ * @param {Error} e error to send or {String} message
398
  * @param {CallStats} cs callstats instance related to the error (optional)
457
  * @param {CallStats} cs callstats instance related to the error (optional)
399
  */
458
  */
400
-CallStats.sendUnhandledError = _try_catch(function (e, cs) {
459
+CallStats.sendApplicationLog = _try_catch(function (e, cs) {
401
     CallStats._reportError
460
     CallStats._reportError
402
-        .call(cs, wrtcFuncNames.applicationError, e, null);
461
+        .call(cs, wrtcFuncNames.applicationLog, e, null);
403
 });
462
 });
404
 
463
 
405
 module.exports = CallStats;
464
 module.exports = CallStats;

+ 20
- 26
modules/statistics/statistics.js Dosyayı Görüntüle

251
         CallStats.sendDominantSpeakerEvent(this.callstats);
251
         CallStats.sendDominantSpeakerEvent(this.callstats);
252
 };
252
 };
253
 
253
 
254
+/**
255
+ * Notifies about active device.
256
+ * @param {{deviceList: {String:String}}} list of devices with their data
257
+ */
258
+Statistics.sendАctiveDeviceListEvent = function (devicesData) {
259
+    if (Statistics.callsStatsInstances.length) {
260
+        Statistics.callsStatsInstances.forEach(function (cs) {
261
+            CallStats.sendАctiveDeviceListEvent(devicesData, cs);
262
+        });
263
+    } else {
264
+        CallStats.sendАctiveDeviceListEvent(devicesData, null);
265
+    }
266
+};
267
+
254
 /**
268
 /**
255
  * Lets the underlying statistics module know where is given SSRC rendered by
269
  * Lets the underlying statistics module know where is given SSRC rendered by
256
  * providing renderer tag ID.
270
  * providing renderer tag ID.
350
 };
364
 };
351
 
365
 
352
 /**
366
 /**
353
- * Notifies CallStats that there is unhandled exception.
367
+ * Adds to CallStats an application log.
354
  *
368
  *
355
- * @param {Error} e error to send
369
+ * @param {String} a log message to send or an {Error} object to be reported
356
  */
370
  */
357
-Statistics.sendUnhandledError = function (e) {
371
+Statistics.sendLog = function (m) {
358
     if (Statistics.callsStatsInstances.length) {
372
     if (Statistics.callsStatsInstances.length) {
359
         Statistics.callsStatsInstances.forEach(function (cs) {
373
         Statistics.callsStatsInstances.forEach(function (cs) {
360
-            CallStats.sendUnhandledError(e, cs);
374
+            CallStats.sendApplicationLog(m, cs);
361
         });
375
         });
362
     } else {
376
     } else {
363
-        CallStats.sendUnhandledError(e, null);
377
+        CallStats.sendApplicationLog(m, null);
364
     }
378
     }
365
 };
379
 };
366
 
380
 
367
-/**
368
- * Adds to CallStats an application log.
369
- *
370
- * @param {String} a log message to send
371
- */
372
-Statistics.sendLog = function (m) {
373
-    // uses  the same field for cs stat as unhandled error
374
-    Statistics.sendUnhandledError(m);
375
-};
376
-
377
-/**
378
- * Adds to CallStats an application log.
379
- *
380
- * @param {String} a log message to send
381
- */
382
-Statistics.prototype.sendLog = function (m) {
383
-    // uses  the same field for cs stat as unhandled error
384
-    CallStats.sendUnhandledError(m, this.callstats);
385
-};
386
-
387
 /**
381
 /**
388
  * Sends the given feedback through CallStats.
382
  * Sends the given feedback through CallStats.
389
  *
383
  *
406
     if (error instanceof JitsiTrackError && error.gum) {
400
     if (error instanceof JitsiTrackError && error.gum) {
407
         Statistics.sendGetUserMediaFailed(error);
401
         Statistics.sendGetUserMediaFailed(error);
408
     } else {
402
     } else {
409
-        Statistics.sendUnhandledError(error);
403
+        Statistics.sendLog(error);
410
     }
404
     }
411
 };
405
 };
412
 
406
 

+ 23
- 10
modules/xmpp/ChatRoom.js Dosyayı Görüntüle

87
     this.phoneNumber = null;
87
     this.phoneNumber = null;
88
     this.phonePin = null;
88
     this.phonePin = null;
89
     this.connectionTimes = {};
89
     this.connectionTimes = {};
90
+    this.participantPropertyListener = null;
90
 }
91
 }
91
 
92
 
92
 ChatRoom.prototype.initPresenceMap = function () {
93
 ChatRoom.prototype.initPresenceMap = function () {
325
         {
326
         {
326
             case "nick":
327
             case "nick":
327
                 if(!member.isFocus) {
328
                 if(!member.isFocus) {
328
-                    var displayName = !this.xmpp.options.displayJids
329
-                        ? member.nick : Strophe.getResourceFromJid(from);
329
+                    var displayName = this.xmpp.options.displayJids
330
+                        ? Strophe.getResourceFromJid(from) : member.nick;
330
 
331
 
331
                     if (displayName && displayName.length > 0) {
332
                     if (displayName && displayName.length > 0) {
332
                         this.eventEmitter.emit(
333
                         this.eventEmitter.emit(
351
                 this.phonePin = att.pin || null;
352
                 this.phonePin = att.pin || null;
352
                 this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);
353
                 this.eventEmitter.emit(XMPPEvents.PHONE_NUMBER_CHANGED);
353
                 break;
354
                 break;
354
-            default :
355
+            default:
355
                 this.processNode(node, from);
356
                 this.processNode(node, from);
356
         }
357
         }
357
     }
358
     }
369
     }
370
     }
370
 };
371
 };
371
 
372
 
373
+/**
374
+ * Sets the special listener to be used for "command"s whose name starts with
375
+ * "jitsi_participant_".
376
+ */
377
+ChatRoom.prototype.setParticipantPropertyListener = function (listener) {
378
+    this.participantPropertyListener = listener;
379
+};
380
+
372
 ChatRoom.prototype.processNode = function (node, from) {
381
 ChatRoom.prototype.processNode = function (node, from) {
373
     // make sure we catch all errors coming from any handler
382
     // make sure we catch all errors coming from any handler
374
     // otherwise we can remove the presence handler from strophe
383
     // otherwise we can remove the presence handler from strophe
375
     try {
384
     try {
376
         var tagHandler = this.presHandlers[node.tagName];
385
         var tagHandler = this.presHandlers[node.tagName];
377
-        if(tagHandler)
386
+        if (node.tagName.startsWith("jitsi_participant_")) {
387
+            tagHandler = this.participantPropertyListener;
388
+        }
389
+
390
+        if(tagHandler) {
378
             tagHandler(node, Strophe.getResourceFromJid(from), from);
391
             tagHandler(node, Strophe.getResourceFromJid(from), from);
392
+        }
379
     } catch (e) {
393
     } catch (e) {
380
         GlobalOnErrorHandler.callErrorHandler(e);
394
         GlobalOnErrorHandler.callErrorHandler(e);
381
         logger.error('Error processing:' + node.tagName + ' node.', e);
395
         logger.error('Error processing:' + node.tagName + ' node.', e);
560
 
574
 
561
 ChatRoom.prototype.addToPresence = function (key, values) {
575
 ChatRoom.prototype.addToPresence = function (key, values) {
562
     values.tagName = key;
576
     values.tagName = key;
563
-    this.presMap["nodes"].push(values);
577
+    this.removeFromPresence(key);
578
+    this.presMap.nodes.push(values);
564
 };
579
 };
565
 
580
 
566
 ChatRoom.prototype.removeFromPresence = function (key) {
581
 ChatRoom.prototype.removeFromPresence = function (key) {
567
-    for(var i = 0; i < this.presMap.nodes.length; i++)
568
-    {
569
-        if(key === this.presMap.nodes[i].tagName)
570
-            this.presMap.nodes.splice(i, 1);
571
-    }
582
+    var nodes = this.presMap.nodes.filter(function(node) {
583
+        return key !== node.tagName;});
584
+    this.presMap.nodes = nodes;
572
 };
585
 };
573
 
586
 
574
 ChatRoom.prototype.addPresenceListener = function (name, handler) {
587
 ChatRoom.prototype.addPresenceListener = function (name, handler) {

+ 2
- 1
service/RTC/RTCEvents.js Dosyayı Görüntüle

7
     AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed",
7
     AVAILABLE_DEVICES_CHANGED: "rtc.available_devices_changed",
8
     TRACK_ATTACHED: "rtc.track_attached",
8
     TRACK_ATTACHED: "rtc.track_attached",
9
     AUDIO_OUTPUT_DEVICE_CHANGED: "rtc.audio_output_device_changed",
9
     AUDIO_OUTPUT_DEVICE_CHANGED: "rtc.audio_output_device_changed",
10
-    DEVICE_LIST_CHANGED: "rtc.device_list_changed"
10
+    DEVICE_LIST_CHANGED: "rtc.device_list_changed",
11
+    DEVICE_LIST_AVAILABLE: "rtc.device_list_available"
11
 };
12
 };
12
 
13
 
13
 module.exports = RTCEvents;
14
 module.exports = RTCEvents;

Loading…
İptal
Kaydet