瀏覽代碼

Adds server-side speaker stats handling.

When the main domain advertises component with type 'speakerstats' every participant will send message to the component with the name of the room where this happen.
dev1
damencho 6 年之前
父節點
當前提交
6eb3157a84

+ 2
- 1
JitsiConferenceEventManager.js 查看文件

@@ -431,7 +431,8 @@ JitsiConferenceEventManager.prototype.setupRTCListeners = function() {
431 431
             }
432 432
             if (conference.statistics && conference.myUserId() === id) {
433 433
                 // We are the new dominant speaker.
434
-                conference.statistics.sendDominantSpeakerEvent();
434
+                conference.statistics.sendDominantSpeakerEvent(
435
+                    conference.room.roomjid);
435 436
             }
436 437
         });
437 438
 

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

@@ -52,10 +52,10 @@ export default class SpeakerStatsCollector {
52 52
     _onDominantSpeaker(dominantSpeakerId) {
53 53
         const oldDominantSpeaker
54 54
             = this.stats.users[this.stats.dominantSpeakerId];
55
-        const newDominantSpaker = this.stats.users[dominantSpeakerId];
55
+        const newDominantSpeaker = this.stats.users[dominantSpeakerId];
56 56
 
57 57
         oldDominantSpeaker && oldDominantSpeaker.setIsDominantSpeaker(false);
58
-        newDominantSpaker && newDominantSpaker.setIsDominantSpeaker(true);
58
+        newDominantSpeaker && newDominantSpeaker.setIsDominantSpeaker(true);
59 59
         this.stats.dominantSpeakerId = dominantSpeakerId;
60 60
     }
61 61
 

+ 5
- 1
modules/statistics/statistics.js 查看文件

@@ -498,11 +498,15 @@ Statistics.prototype.sendScreenSharingEvent
498 498
 /**
499 499
  * Notifies the statistics module that we are now the dominant speaker of the
500 500
  * conference.
501
+ * @param {String} roomJid - The room jid where the speaker event occurred.
501 502
  */
502
-Statistics.prototype.sendDominantSpeakerEvent = function() {
503
+Statistics.prototype.sendDominantSpeakerEvent = function(roomJid) {
503 504
     for (const cs of this.callsStatsInstances.values()) {
504 505
         cs.sendDominantSpeakerEvent();
505 506
     }
507
+
508
+    // xmpp send dominant speaker event
509
+    this.xmpp.sendDominantSpeakerEvent(roomJid);
506 510
 };
507 511
 
508 512
 /**

+ 48
- 12
modules/xmpp/Caps.js 查看文件

@@ -119,27 +119,63 @@ export default class Caps extends Listenable {
119 119
         if (!user || !(user.version in this.versionToCapabilities)) {
120 120
             const node = user ? `${user.node}#${user.version}` : null;
121 121
 
122
-
123
-            return new Promise((resolve, reject) =>
124
-                this.disco.info(jid, node, response => {
125
-                    const features = new Set();
126
-
127
-                    $(response)
128
-                        .find('>query>feature')
129
-                        .each(
130
-                            (idx, el) => features.add(el.getAttribute('var')));
122
+            return this._getDiscoInfo(jid, node, timeout)
123
+                .then(({ features }) => {
131 124
                     if (user) {
132 125
                         // TODO: Maybe use the version + node + hash as keys?
133 126
                         this.versionToCapabilities[user.version] = features;
134 127
                     }
135
-                    resolve(features);
136
-                }, reject, timeout)
137
-            );
128
+
129
+                    return features;
130
+                });
138 131
         }
139 132
 
140 133
         return Promise.resolve(this.versionToCapabilities[user.version]);
141 134
     }
142 135
 
136
+    /**
137
+     * Returns a set with the features for a host.
138
+     * @param {String} jid the jid of the host
139
+     * @param {int} timeout the timeout in ms for reply from the host.
140
+     * @returns {Promise<Set<String>, Error>}
141
+     */
142
+    getFeaturesAndIdentities(jid, timeout = 5000) {
143
+        return this._getDiscoInfo(jid, null, timeout);
144
+    }
145
+
146
+    /**
147
+     * Returns a set with the features and identities for a host.
148
+     * @param {String} jid the jid of the host
149
+     * @param {String|null} node the node to query
150
+     * @param {int} timeout the timeout in ms for reply from the host.
151
+     * @returns {Promise<Object>}
152
+     * @private
153
+     */
154
+    _getDiscoInfo(jid, node, timeout) {
155
+        return new Promise((resolve, reject) =>
156
+            this.disco.info(jid, node, response => {
157
+                const features = new Set();
158
+                const identities = new Set();
159
+
160
+                $(response)
161
+                    .find('>query>feature')
162
+                    .each(
163
+                        (_, el) => features.add(el.getAttribute('var')));
164
+                $(response)
165
+                    .find('>query>identity')
166
+                    .each(
167
+                        (_, el) => identities.add({
168
+                            type: el.getAttribute('type'),
169
+                            name: el.getAttribute('name'),
170
+                            category: el.getAttribute('category')
171
+                        }));
172
+                resolve({
173
+                    features,
174
+                    identities });
175
+            }, reject, timeout)
176
+        );
177
+    }
178
+
143 179
     /**
144 180
      * Adds ChatRoom instance to the list of rooms. Adds listeners to the room
145 181
      * and adds "c" element to the presences of the room.

+ 0
- 18
modules/xmpp/strophe.ping.js 查看文件

@@ -81,24 +81,6 @@ class PingConnectionPlugin extends ConnectionPlugin {
81 81
 
82 82
     /* eslint-enable max-params */
83 83
 
84
-    /**
85
-     * Checks if given <tt>jid</tt> has XEP-0199 ping support.
86
-     * @param jid the JID to be checked for ping support.
87
-     * @param callback function with boolean argument which will be
88
-     * <tt>true</tt> if XEP-0199 ping is supported by given <tt>jid</tt>
89
-     */
90
-    hasPingSupport(jid, callback) {
91
-        this.xmpp.caps.getFeatures(jid).then(features =>
92
-            callback(features.has('urn:xmpp:ping')), error => {
93
-            const errmsg = 'Ping feature discovery error';
94
-
95
-            GlobalOnErrorHandler.callErrorHandler(
96
-                new Error(`${errmsg}: ${error}`));
97
-            logger.error(errmsg, error);
98
-            callback(false);
99
-        });
100
-    }
101
-
102 84
     /**
103 85
      * Starts to send ping in given interval to specified remote JID.
104 86
      * This plugin supports only one such task and <tt>stopInterval</tt>

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

@@ -1,7 +1,7 @@
1 1
 /* global $ */
2 2
 
3 3
 import { getLogger } from 'jitsi-meet-logger';
4
-import { Strophe } from 'strophe.js';
4
+import { $msg, Strophe } from 'strophe.js';
5 5
 import 'strophejs-plugin-disco';
6 6
 
7 7
 import RandomUtil from '../util/RandomUtil';
@@ -16,6 +16,7 @@ import initRayo from './strophe.rayo';
16 16
 import initStropheLogger from './strophe.logger';
17 17
 import Listenable from '../util/Listenable';
18 18
 import Caps from './Caps';
19
+import GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
19 20
 
20 21
 const logger = getLogger(__filename);
21 22
 
@@ -154,21 +155,34 @@ export default class XMPP extends Listenable {
154 155
             // Schedule ping ?
155 156
             const pingJid = this.connection.domain;
156 157
 
157
-            this.connection.ping.hasPingSupport(
158
-                pingJid,
159
-                hasPing => {
160
-                    if (hasPing) {
158
+            this.caps.getFeaturesAndIdentities(pingJid)
159
+                .then(({ features, identities }) => {
160
+                    if (features.has(Strophe.NS.PING)) {
161 161
                         this.connection.ping.startInterval(pingJid);
162 162
                     } else {
163 163
                         logger.warn(`Ping NOT supported by ${pingJid}`);
164 164
                     }
165
+
166
+                    // check for speakerstats
167
+                    identities.forEach(identity => {
168
+                        if (identity.type === 'speakerstats') {
169
+                            this.speakerStatsComponentAddress = identity.name;
170
+                        }
171
+                    });
172
+                })
173
+                .catch(error => {
174
+                    const errmsg = 'Feature discovery error';
175
+
176
+                    GlobalOnErrorHandler.callErrorHandler(
177
+                        new Error(`${errmsg}: ${error}`));
178
+                    logger.error(errmsg, error);
165 179
                 });
166 180
 
167 181
             if (credentials.password) {
168 182
                 this.authenticatedUser = true;
169 183
             }
170 184
             if (this.connection && this.connection.connected
171
-                    && Strophe.getResourceFromJid(this.connection.jid)) {
185
+                && Strophe.getResourceFromJid(this.connection.jid)) {
172 186
                 // .connected is true while connecting?
173 187
                 // this.connection.send($pres());
174 188
                 this.eventEmitter.emit(
@@ -553,4 +567,25 @@ export default class XMPP extends Listenable {
553 567
 
554 568
         return details;
555 569
     }
570
+
571
+    /**
572
+     * Notifies speaker stats component if available that we are the new
573
+     * dominant speaker in the conference.
574
+     * @param {String} roomJid - The room jid where the speaker event occurred.
575
+     */
576
+    sendDominantSpeakerEvent(roomJid) {
577
+        // no speaker stats component advertised
578
+        if (!this.speakerStatsComponentAddress || !roomJid) {
579
+            return;
580
+        }
581
+
582
+        const msg = $msg({ to: this.speakerStatsComponentAddress });
583
+
584
+        msg.c('speakerstats', {
585
+            xmlns: 'http://jitsi.org/jitmeet',
586
+            room: `${roomJid}` })
587
+            .up();
588
+
589
+        this.connection.send(msg);
590
+    }
556 591
 }

Loading…
取消
儲存