Przeglądaj źródła

Calculates quality based on the resolution and upload.

j8
damencho 9 lat temu
rodzic
commit
a2c71d05e6

+ 16
- 4
conference.js Wyświetl plik

1372
         }
1372
         }
1373
 
1373
 
1374
         room.on(ConferenceEvents.CONNECTION_STATS, function (stats) {
1374
         room.on(ConferenceEvents.CONNECTION_STATS, function (stats) {
1375
-            ConnectionQuality.updateLocalStats(stats, connectionIsInterrupted);
1375
+            ConnectionQuality.updateLocalStats(
1376
+                stats, connectionIsInterrupted, localVideo);
1376
         });
1377
         });
1377
 
1378
 
1378
         ConnectionQuality.addListener(CQEvents.LOCALSTATS_UPDATED,
1379
         ConnectionQuality.addListener(CQEvents.LOCALSTATS_UPDATED,
1382
                 let data = {
1383
                 let data = {
1383
                     bitrate: stats.bitrate,
1384
                     bitrate: stats.bitrate,
1384
                     packetLoss: stats.packetLoss};
1385
                     packetLoss: stats.packetLoss};
1386
+                if (localVideo && localVideo.resolution) {
1387
+                    data.resolution = {
1388
+                        inputHeight: localVideo.resolution
1389
+                    };
1390
+                }
1391
+
1385
                 try {
1392
                 try {
1386
                     room.broadcastEndpointMessage({
1393
                     room.broadcastEndpointMessage({
1387
                         type: this.commands.defaults.CONNECTION_QUALITY,
1394
                         type: this.commands.defaults.CONNECTION_QUALITY,
1394
         room.on(ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
1401
         room.on(ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
1395
             (participant, payload) => {
1402
             (participant, payload) => {
1396
                 switch(payload.type) {
1403
                 switch(payload.type) {
1397
-                    case this.commands.defaults.CONNECTION_QUALITY:
1398
-                        ConnectionQuality.updateRemoteStats(participant.getId(),
1399
-                            payload.values);
1404
+                    case this.commands.defaults.CONNECTION_QUALITY: {
1405
+                        let id = participant.getId();
1406
+                        ConnectionQuality.updateRemoteStats(
1407
+                            id,
1408
+                            payload.values,
1409
+                            APP.UI.getRemoteVideoType(id),
1410
+                            APP.UI.isRemoteVideoMuted(id));
1400
                         break;
1411
                         break;
1412
+                    }
1401
                     default:
1413
                     default:
1402
                         console.warn("Unknown datachannel message", payload);
1414
                         console.warn("Unknown datachannel message", payload);
1403
                 }
1415
                 }

+ 9
- 0
modules/UI/UI.js Wyświetl plik

779
     return VideoLayout.getRemoteVideoType(jid);
779
     return VideoLayout.getRemoteVideoType(jid);
780
 };
780
 };
781
 
781
 
782
+/**
783
+ * Return the mute state of the remote video.
784
+ * @param jid the jid for the remote video
785
+ * @returns the video mute state.
786
+ */
787
+UI.isRemoteVideoMuted = function (jid) {
788
+    return VideoLayout.isRemoteVideoMuted(jid);
789
+};
790
+
782
 UI.connectionIndicatorShowMore = function(id) {
791
 UI.connectionIndicatorShowMore = function(id) {
783
     VideoLayout.showMore(id);
792
     VideoLayout.showMore(id);
784
 };
793
 };

+ 10
- 0
modules/UI/videolayout/VideoLayout.js Wyświetl plik

327
         return smallVideo ? smallVideo.getVideoType() : null;
327
         return smallVideo ? smallVideo.getVideoType() : null;
328
     },
328
     },
329
 
329
 
330
+    /**
331
+     * Return the mute state of the remote video.
332
+     * @param id the id for the remote video
333
+     * @returns {boolean} the video mute state.
334
+     */
335
+    isRemoteVideoMuted (id) {
336
+        let smallVideo = VideoLayout.getSmallVideo(id);
337
+        return smallVideo ? smallVideo.isVideoMuted : null;
338
+    },
339
+
330
     isPinned (id) {
340
     isPinned (id) {
331
         return (pinnedId) ? (id === pinnedId) : false;
341
         return (pinnedId) ? (id === pinnedId) : false;
332
     },
342
     },

+ 107
- 23
modules/connectionquality/connectionquality.js Wyświetl plik

1
+/* global config */
1
 import EventEmitter from "events";
2
 import EventEmitter from "events";
2
 
3
 
3
 import CQEvents from "../../service/connectionquality/CQEvents";
4
 import CQEvents from "../../service/connectionquality/CQEvents";
35
     return (newVal <= oldVal) ? newVal : (9*oldVal + newVal) / 10;
36
     return (newVal <= oldVal) ? newVal : (9*oldVal + newVal) / 10;
36
 }
37
 }
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
+var _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
+var 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 {*} 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.
67
+ */
68
+function calculateQualityUsingUpload(inputHeight, upload) {
69
+    let foundResolution = null;
70
+
71
+    for (let i in _bandwidthMap) {
72
+        let r = _bandwidthMap[i];
73
+        if (r.height <= inputHeight) {
74
+            foundResolution = r;
75
+            break;
76
+        }
77
+    }
78
+
79
+    if (!foundResolution)
80
+        return false;
81
+
82
+    if (upload <= foundResolution.min)
83
+        return 0;
84
+
85
+    return Math.min(
86
+        ((upload - foundResolution.min)*100)
87
+            / (foundResolution.max - foundResolution.min),
88
+        100);
89
+}
90
+
38
 export default {
91
 export default {
39
     /**
92
     /**
40
      * Updates the local statistics
93
      * Updates the local statistics
42
      * @param dontUpdateLocalConnectionQuality {boolean} if true -
95
      * @param dontUpdateLocalConnectionQuality {boolean} if true -
43
      * localConnectionQuality wont be recalculated.
96
      * localConnectionQuality wont be recalculated.
44
      */
97
      */
45
-    updateLocalStats: function (data, dontUpdateLocalConnectionQuality) {
46
-        stats = data;
47
-        if(!dontUpdateLocalConnectionQuality) {
48
-            var newVal = 100 - stats.packetLoss.total;
49
-            localConnectionQuality =
50
-                calculateQuality(newVal, localConnectionQuality);
51
-        }
52
-        eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, localConnectionQuality,
53
-            stats);
98
+    updateLocalStats:
99
+        function (data, dontUpdateLocalConnectionQuality, localVideo) {
100
+            stats = data;
101
+            if(!dontUpdateLocalConnectionQuality) {
102
+                if (!disableQualityBasedOnBandwidth
103
+                    && !localVideo.isMuted()
104
+                    && localVideo.videoType !== 'desktop'
105
+                    && localVideo.resolution) {
106
+                        let val = calculateQualityUsingUpload(
107
+                            localVideo.resolution,
108
+                            data.bitrate.upload);
109
+                        if (val) {
110
+                            localConnectionQuality = val;
111
+                        }
112
+                    } else {
113
+                        var newVal = 100 - stats.packetLoss.total;
114
+                        localConnectionQuality =
115
+                            calculateQuality(newVal, localConnectionQuality);
116
+                    }
117
+            }
118
+            eventEmitter.emit(
119
+                CQEvents.LOCALSTATS_UPDATED, localConnectionQuality, stats);
54
     },
120
     },
55
 
121
 
56
     /**
122
     /**
68
      * @param id the id associated with the statistics
134
      * @param id the id associated with the statistics
69
      * @param data the statistics
135
      * @param data the statistics
70
      */
136
      */
71
-    updateRemoteStats: function (id, data) {
72
-        if (!data || !("packetLoss" in data) || !("total" in data.packetLoss)) {
73
-            eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
74
-            return;
75
-        }
76
-        // Use only the fields we need
77
-        data = {bitrate: data.bitrate, packetLoss: data.packetLoss};
137
+    updateRemoteStats:
138
+        function (id, data, remoteVideoType, isRemoteVideoMuted) {
139
+            if (!data ||
140
+                !("packetLoss" in data) ||
141
+                !("total" in data.packetLoss)) {
142
+                eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, id, null, null);
143
+                return;
144
+            }
145
+
146
+            let inputResolution = data.resolution;
147
+            // Use only the fields we need
148
+            data = {bitrate: data.bitrate, packetLoss: data.packetLoss};
78
 
149
 
79
-        remoteStats[id] = data;
150
+            remoteStats[id] = data;
80
 
151
 
81
-        var newVal = 100 - data.packetLoss.total;
82
-        var oldVal = remoteConnectionQuality[id];
83
-        remoteConnectionQuality[id] = calculateQuality(newVal, oldVal || 100);
152
+            if (disableQualityBasedOnBandwidth
153
+                || isRemoteVideoMuted
154
+                || remoteVideoType === 'desktop'
155
+                || !inputResolution) {
156
+                var newVal = 100 - data.packetLoss.total;
157
+                var oldVal = remoteConnectionQuality[id];
158
+                remoteConnectionQuality[id]
159
+                    = calculateQuality(newVal, oldVal || 100);
160
+            } else {
161
+                let val = calculateQualityUsingUpload(
162
+                    inputResolution.inputHeight,
163
+                    data.bitrate.upload);
164
+                if (val) {
165
+                    remoteConnectionQuality[id] = val;
166
+                }
167
+            }
84
 
168
 
85
-        eventEmitter.emit(
86
-            CQEvents.REMOTESTATS_UPDATED, id, remoteConnectionQuality[id],
87
-            remoteStats[id]);
169
+            eventEmitter.emit(
170
+                CQEvents.REMOTESTATS_UPDATED, id,
171
+                remoteConnectionQuality[id], remoteStats[id]);
88
     },
172
     },
89
 
173
 
90
     /**
174
     /**

Ładowanie…
Anuluj
Zapisz