소스 검색

Merge pull request #1094 from bgrozev/conn-quality

Conn quality
master
Дамян Минков 9 년 전
부모
커밋
e679509c56
4개의 변경된 파일38개의 추가작업 그리고 299개의 파일을 삭제
  1. 17
    72
      conference.js
  2. 21
    24
      modules/UI/videolayout/ConnectionIndicator.js
  3. 0
    196
      modules/connectionquality/connectionquality.js
  4. 0
    7
      service/connectionquality/CQEvents.js

+ 17
- 72
conference.js 파일 보기

4
 import ContactList from './modules/UI/side_pannels/contactlist/ContactList';
4
 import ContactList from './modules/UI/side_pannels/contactlist/ContactList';
5
 
5
 
6
 import AuthHandler from './modules/UI/authentication/AuthHandler';
6
 import AuthHandler from './modules/UI/authentication/AuthHandler';
7
-
8
-import ConnectionQuality from './modules/connectionquality/connectionquality';
9
-
10
 import Recorder from './modules/recorder/Recorder';
7
 import Recorder from './modules/recorder/Recorder';
11
 
8
 
12
-import CQEvents from './service/connectionquality/CQEvents';
13
-import UIEvents from './service/UI/UIEvents';
14
-
15
 import mediaDeviceHelper from './modules/devices/mediaDeviceHelper';
9
 import mediaDeviceHelper from './modules/devices/mediaDeviceHelper';
16
 
10
 
17
 import {reportError} from './modules/util/helpers';
11
 import {reportError} from './modules/util/helpers';
18
 
12
 
13
+import UIEvents from './service/UI/UIEvents';
19
 import UIUtil from './modules/UI/util/UIUtil';
14
 import UIUtil from './modules/UI/util/UIUtil';
20
 
15
 
21
 const ConnectionEvents = JitsiMeetJS.events.connection;
16
 const ConnectionEvents = JitsiMeetJS.events.connection;
27
 const TrackEvents = JitsiMeetJS.events.track;
22
 const TrackEvents = JitsiMeetJS.events.track;
28
 const TrackErrors = JitsiMeetJS.errors.track;
23
 const TrackErrors = JitsiMeetJS.errors.track;
29
 
24
 
30
-let room, connection, localAudio, localVideo;
25
+const ConnectionQualityEvents = JitsiMeetJS.events.connectionQuality;
31
 
26
 
32
-/**
33
- * Indicates whether the connection is interrupted or not.
34
- */
35
-let connectionIsInterrupted = false;
27
+let room, connection, localAudio, localVideo;
36
 
28
 
37
 /**
29
 /**
38
  * Indicates whether extension external installation is in progress or not.
30
  * Indicates whether extension external installation is in progress or not.
45
  * Known custom conference commands.
37
  * Known custom conference commands.
46
  */
38
  */
47
 const commands = {
39
 const commands = {
48
-    CONNECTION_QUALITY: "stats",
49
     EMAIL: "email",
40
     EMAIL: "email",
50
     AVATAR_URL: "avatar-url",
41
     AVATAR_URL: "avatar-url",
51
     AVATAR_ID: "avatar-id",
42
     AVATAR_ID: "avatar-id",
685
      * false otherwise.
676
      * false otherwise.
686
      */
677
      */
687
     isConnectionInterrupted () {
678
     isConnectionInterrupted () {
688
-        return connectionIsInterrupted;
679
+        return this._room.isConnectionInterrupted();
689
     },
680
     },
690
     /**
681
     /**
691
      * Finds JitsiParticipant for given id.
682
      * Finds JitsiParticipant for given id.
774
      * Returns the stats.
765
      * Returns the stats.
775
      */
766
      */
776
     getStats() {
767
     getStats() {
777
-        return ConnectionQuality.getStats();
768
+        return room.connectionQuality.getStats();
778
     },
769
     },
779
     // end used by torture
770
     // end used by torture
780
 
771
 
1108
         room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
1099
         room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
1109
             APP.UI.mucJoined();
1100
             APP.UI.mucJoined();
1110
             APP.API.notifyConferenceJoined(APP.conference.roomName);
1101
             APP.API.notifyConferenceJoined(APP.conference.roomName);
1111
-            connectionIsInterrupted = false;
1112
             APP.UI.markVideoInterrupted(false);
1102
             APP.UI.markVideoInterrupted(false);
1113
         });
1103
         });
1114
 
1104
 
1257
         }
1247
         }
1258
 
1248
 
1259
         room.on(ConferenceEvents.CONNECTION_INTERRUPTED, () => {
1249
         room.on(ConferenceEvents.CONNECTION_INTERRUPTED, () => {
1260
-            connectionIsInterrupted = true;
1261
-            ConnectionQuality.updateLocalConnectionQuality(0);
1262
             APP.UI.showLocalConnectionInterrupted(true);
1250
             APP.UI.showLocalConnectionInterrupted(true);
1263
         });
1251
         });
1264
 
1252
 
1265
         room.on(ConferenceEvents.CONNECTION_RESTORED, () => {
1253
         room.on(ConferenceEvents.CONNECTION_RESTORED, () => {
1266
-            connectionIsInterrupted = false;
1267
             APP.UI.showLocalConnectionInterrupted(false);
1254
             APP.UI.showLocalConnectionInterrupted(false);
1268
         });
1255
         });
1269
 
1256
 
1315
             });
1302
             });
1316
         }
1303
         }
1317
 
1304
 
1318
-        room.on(ConferenceEvents.CONNECTION_STATS, function (stats) {
1319
-            // if we say video muted we will use old method of calculating
1320
-            // quality and will not depend on localVideo if it is missing
1321
-            ConnectionQuality.updateLocalStats(
1322
-                stats,
1323
-                connectionIsInterrupted,
1324
-                localVideo ? localVideo.videoType : undefined,
1325
-                localVideo ? localVideo.isMuted() : true,
1326
-                localVideo ? localVideo.resolution : null);
1327
-        });
1328
-
1329
-        ConnectionQuality.addListener(CQEvents.LOCALSTATS_UPDATED,
1330
-            (percent, stats) => {
1331
-                APP.UI.updateLocalStats(percent, stats);
1332
-                // Send only the data that remote participants care about.
1333
-                let data = {
1334
-                    bitrate: stats.bitrate,
1335
-                    packetLoss: stats.packetLoss};
1336
-                if (localVideo && localVideo.resolution) {
1337
-                    data.resolution = localVideo.resolution;
1338
-                }
1339
-
1340
-                try {
1341
-                    room.broadcastEndpointMessage({
1342
-                        type: this.commands.defaults.CONNECTION_QUALITY,
1343
-                        values: data });
1344
-                } catch (e) {
1345
-                    reportError(e);
1346
-                }
1347
-            });
1305
+        room.on(ConnectionQualityEvents.LOCAL_STATS_UPDATED,
1306
+            (stats) => {
1307
+                APP.UI.updateLocalStats(stats.connectionQuality, stats);
1348
 
1308
 
1349
-        room.on(ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
1350
-            (participant, payload) => {
1351
-                switch(payload.type) {
1352
-                    case this.commands.defaults.CONNECTION_QUALITY: {
1353
-                        let remoteVideo = participant.getTracks()
1354
-                            .find(tr => tr.isVideoTrack());
1355
-                        ConnectionQuality.updateRemoteStats(
1356
-                            participant.getId(),
1357
-                            payload.values,
1358
-                            remoteVideo ? remoteVideo.videoType : undefined,
1359
-                            remoteVideo ? remoteVideo.isMuted() : undefined);
1360
-                        break;
1361
-                    }
1362
-                    default:
1363
-                        console.warn("Unknown datachannel message", payload);
1364
-                }
1365
-            });
1309
+        });
1366
 
1310
 
1367
-        ConnectionQuality.addListener(CQEvents.REMOTESTATS_UPDATED,
1368
-            (id, percent, stats) => {
1369
-                APP.UI.updateRemoteStats(id, percent, stats);
1370
-            });
1311
+        room.on(ConnectionQualityEvents.REMOTE_STATS_UPDATED,
1312
+            (id, stats) => {
1313
+                APP.UI.updateRemoteStats(id, stats.connectionQuality, stats);
1314
+        });
1371
 
1315
 
1372
         room.addCommandListener(this.commands.defaults.ETHERPAD, ({value}) => {
1316
         room.addCommandListener(this.commands.defaults.ETHERPAD, ({value}) => {
1373
             APP.UI.initEtherpad(value);
1317
             APP.UI.initEtherpad(value);
1378
             APP.UI.setUserEmail(from, data.value);
1322
             APP.UI.setUserEmail(from, data.value);
1379
         });
1323
         });
1380
 
1324
 
1381
-        room.addCommandListener(this.commands.defaults.AVATAR_URL,
1382
-        (data, from) => {
1383
-            APP.UI.setUserAvatarUrl(from, data.value);
1325
+        room.addCommandListener(
1326
+            this.commands.defaults.AVATAR_URL,
1327
+            (data, from) => {
1328
+                APP.UI.setUserAvatarUrl(from, data.value);
1384
         });
1329
         });
1385
 
1330
 
1386
         room.addCommandListener(this.commands.defaults.AVATAR_ID,
1331
         room.addCommandListener(this.commands.defaults.AVATAR_ID,

+ 21
- 24
modules/UI/videolayout/ConnectionIndicator.js 파일 보기

4
 import VideoLayout from "./VideoLayout";
4
 import VideoLayout from "./VideoLayout";
5
 import UIUtil from "../util/UIUtil";
5
 import UIUtil from "../util/UIUtil";
6
 
6
 
7
+/**
8
+ * Maps a connection quality value (in percent) to the width of the "full" icon.
9
+ */
10
+const qualityToWidth = [
11
+    // Full (5 bars)
12
+    {percent: 80, width: "100%"},
13
+    // 4 bars
14
+    {percent: 60, width: "80%"},
15
+    // 3 bars
16
+    {percent: 40, width: "55%"},
17
+    // 2 bars
18
+    {percent: 20, width: "40%"},
19
+    // 1 bar
20
+    {percent: 0, width: "20%"}
21
+    // Note: we never show 0 bars.
22
+];
23
+
7
 /**
24
 /**
8
  * Constructs new connection indicator.
25
  * Constructs new connection indicator.
9
  * @param videoContainer the video container associated with the indicator.
26
  * @param videoContainer the video container associated with the indicator.
24
     this.create();
41
     this.create();
25
 }
42
 }
26
 
43
 
27
-/**
28
- * Values for the connection quality
29
- * @type {{98: string,
30
- *         81: string,
31
- *         64: string,
32
- *         47: string,
33
- *         30: string,
34
- *         0: string}}
35
- */
36
-ConnectionIndicator.connectionQualityValues = {
37
-    98: "100%", //full
38
-    81: "80%",//4 bars
39
-    64: "55%",//3 bars
40
-    47: "40%",//2 bars
41
-    30: "20%",//1 bar
42
-    0: "0"//empty
43
-};
44
-
45
 ConnectionIndicator.getIP = function(value) {
44
 ConnectionIndicator.getIP = function(value) {
46
     return value.substring(0, value.lastIndexOf(":"));
45
     return value.substring(0, value.lastIndexOf(":"));
47
 };
46
 };
360
             this.resolution = object.resolution;
359
             this.resolution = object.resolution;
361
         }
360
         }
362
     }
361
     }
363
-    for (var quality in ConnectionIndicator.connectionQualityValues) {
364
-        if (percent >= quality) {
365
-            this.fullIcon.style.width =
366
-                ConnectionIndicator.connectionQualityValues[quality];
367
-        }
368
-    }
362
+
363
+    let width = qualityToWidth.find(x => percent >= x.percent);
364
+    this.fullIcon.style.width = width.width;
365
+
369
     if (object && typeof object.isResolutionHD === 'boolean') {
366
     if (object && typeof object.isResolutionHD === 'boolean') {
370
         this.isResolutionHD = object.isResolutionHD;
367
         this.isResolutionHD = object.isResolutionHD;
371
     }
368
     }

+ 0
- 196
modules/connectionquality/connectionquality.js 파일 보기

1
-/* global config */
2
-import EventEmitter from "events";
3
-
4
-import CQEvents from "../../service/connectionquality/CQEvents";
5
-
6
-const eventEmitter = new EventEmitter();
7
-
8
-/**
9
- * local stats
10
- * @type {{}}
11
- */
12
-var stats = {};
13
-
14
-/**
15
- * remote stats
16
- * @type {{}}
17
- */
18
-var remoteStats = {};
19
-
20
-/**
21
- * Quality percent( 100% - good, 0% - bad.) for the local user.
22
- */
23
-var localConnectionQuality = 100;
24
-
25
-/**
26
- * Quality percent( 100% - good, 0% - bad.) stored per id.
27
- */
28
-var remoteConnectionQuality = {};
29
-
30
-/**
31
- * Calculates the quality percent based on passed new and old value.
32
- * @param newVal the new value
33
- * @param oldVal the old value
34
- */
35
-function calculateQuality(newVal, oldVal) {
36
-    return (newVal <= oldVal) ? newVal : (9*oldVal + newVal) / 10;
37
-}
38
-
39
-// webrtc table describing simulcast resolutions and used bandwidth
40
-// https://chromium.googlesource.com/external/webrtc/+/master/webrtc/media/engine/simulcast.cc#42
41
-const _bandwidthMap = [
42
-    { width: 1920, height: 1080, layers:3, max: 5000, min: 800 },
43
-    { width: 1280, height: 720,  layers:3, max: 2500, min: 600 },
44
-    { width: 960,  height: 540,  layers:3, max: 900,  min: 450 },
45
-    { width: 640,  height: 360,  layers:2, max: 700,  min: 150 },
46
-    { width: 480,  height: 270,  layers:2, max: 450,  min: 150 },
47
-    { width: 320,  height: 180,  layers:1, max: 200,  min: 30 }
48
-];
49
-
50
-/**
51
- * We disable quality calculations based on bandwidth if simulcast is disabled,
52
- * or enable it in case of no simulcast and we force it.
53
- * @type {boolean}
54
- */
55
-const disableQualityBasedOnBandwidth =
56
-    config.forceQualityBasedOnBandwidth ? false : config.disableSimulcast;
57
-
58
-/**
59
- * Calculates the quality percentage based on the input resolution height and
60
- * the upload reported by the client. The value is based on the interval from
61
- * _bandwidthMap.
62
- * @param inputHeight the resolution used to open the camera.
63
- * @param upload the upload rate reported by client.
64
- * @returns {int} the percent of upload based on _bandwidthMap and maximum value
65
- * of 100, as values of the map are approximate and clients can stream above
66
- * those values. Returns undefined if no result is found.
67
- */
68
-function calculateQualityUsingUpload(inputHeight, upload) {
69
-    // found resolution from _bandwidthMap which height is equal or less than
70
-    // the inputHeight
71
-    let foundResolution = _bandwidthMap.find((r) => (r.height <= inputHeight));
72
-
73
-    if (!foundResolution)
74
-        return undefined;
75
-
76
-    if (upload <= foundResolution.min)
77
-        return 0;
78
-
79
-    return Math.min(
80
-        ((upload - foundResolution.min)*100)
81
-            / (foundResolution.max - foundResolution.min),
82
-        100);
83
-}
84
-
85
-export default {
86
-    /**
87
-     * Updates the local statistics
88
-     * @param data new statistics
89
-     * @param dontUpdateLocalConnectionQuality {boolean} if true -
90
-     * localConnectionQuality wont be recalculated.
91
-     * @param videoType the local video type
92
-     * @param isMuted current state of local video, whether it is muted
93
-     * @param resolution the current resolution used by local video
94
-     */
95
-    updateLocalStats:
96
-        function (data, dontUpdateLocalConnectionQuality,
97
-                  videoType, isMuted, resolution) {
98
-            stats = data;
99
-            if(!dontUpdateLocalConnectionQuality) {
100
-                let val = this._getNewQualityValue(
101
-                    stats,
102
-                    localConnectionQuality,
103
-                    videoType,
104
-                    isMuted,
105
-                    resolution);
106
-                if (val !== undefined)
107
-                    localConnectionQuality = val;
108
-            }
109
-            eventEmitter.emit(
110
-                CQEvents.LOCALSTATS_UPDATED, localConnectionQuality, stats);
111
-    },
112
-
113
-    /**
114
-     * Updates only the localConnectionQuality value
115
-     * @param values {int} the new value. should be from 0 - 100.
116
-     */
117
-    updateLocalConnectionQuality: function (value) {
118
-        localConnectionQuality = value;
119
-        eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, localConnectionQuality,
120
-            stats);
121
-    },
122
-
123
-    /**
124
-     * Updates remote statistics
125
-     * @param id the id associated with the statistics
126
-     * @param data the statistics received
127
-     * @param remoteVideoType the video type of the remote video
128
-     * @param isRemoteVideoMuted whether remote video is muted
129
-     */
130
-    updateRemoteStats:
131
-        function (id, data, remoteVideoType, isRemoteVideoMuted) {
132
-            if (!data ||
133
-                !("packetLoss" in data) ||
134
-                !("total" in data.packetLoss)) {
135
-                eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
136
-                return;
137
-            }
138
-
139
-            let inputResolution = data.resolution;
140
-            // Use only the fields we need
141
-            data = {bitrate: data.bitrate, packetLoss: data.packetLoss};
142
-
143
-            remoteStats[id] = data;
144
-
145
-            let val = this._getNewQualityValue(
146
-                data,
147
-                remoteConnectionQuality[id],
148
-                remoteVideoType,
149
-                isRemoteVideoMuted,
150
-                inputResolution);
151
-            if (val !== undefined)
152
-                remoteConnectionQuality[id] = val;
153
-
154
-            eventEmitter.emit(
155
-                CQEvents.REMOTESTATS_UPDATED, id,
156
-                remoteConnectionQuality[id], remoteStats[id]);
157
-    },
158
-
159
-    /**
160
-     * Returns the new quality value based on the input parameters.
161
-     * Used to calculate remote and local values.
162
-     * @param data the data
163
-     * @param lastQualityValue the last value we calculated
164
-     * @param videoType need to check whether we are screen sharing
165
-     * @param isMuted is video muted
166
-     * @param resolution the input resolution used by the camera
167
-     * @returns {*} the newly calculated value or undefined if no result
168
-     * @private
169
-     */
170
-    _getNewQualityValue:
171
-        function (data, lastQualityValue, videoType, isMuted, resolution) {
172
-            if (disableQualityBasedOnBandwidth
173
-                || isMuted
174
-                || videoType === 'desktop'
175
-                || !resolution) {
176
-                return calculateQuality(
177
-                    100 - data.packetLoss.total,
178
-                    lastQualityValue || 100);
179
-            } else {
180
-                return calculateQualityUsingUpload(
181
-                    resolution,
182
-                    data.bitrate.upload);
183
-            }
184
-    },
185
-
186
-    /**
187
-     * Returns the local statistics.
188
-     */
189
-    getStats: function () {
190
-        return stats;
191
-    },
192
-
193
-    addListener: function (type, listener) {
194
-        eventEmitter.on(type, listener);
195
-    }
196
-};

+ 0
- 7
service/connectionquality/CQEvents.js 파일 보기

1
-var CQEvents = {
2
-    LOCALSTATS_UPDATED: "cq.localstats_updated",
3
-    REMOTESTATS_UPDATED: "cq.remotestats_updated",
4
-    STOP: "cq.stop"
5
-};
6
-
7
-module.exports = CQEvents;

Loading…
취소
저장