Преглед изворни кода

Calculates quality based on the resolution and upload.

j8
damencho пре 9 година
родитељ
комит
a2c71d05e6
4 измењених фајлова са 142 додато и 27 уклоњено
  1. 16
    4
      conference.js
  2. 9
    0
      modules/UI/UI.js
  3. 10
    0
      modules/UI/videolayout/VideoLayout.js
  4. 107
    23
      modules/connectionquality/connectionquality.js

+ 16
- 4
conference.js Прегледај датотеку

@@ -1372,7 +1372,8 @@ export default {
1372 1372
         }
1373 1373
 
1374 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 1379
         ConnectionQuality.addListener(CQEvents.LOCALSTATS_UPDATED,
@@ -1382,6 +1383,12 @@ export default {
1382 1383
                 let data = {
1383 1384
                     bitrate: stats.bitrate,
1384 1385
                     packetLoss: stats.packetLoss};
1386
+                if (localVideo && localVideo.resolution) {
1387
+                    data.resolution = {
1388
+                        inputHeight: localVideo.resolution
1389
+                    };
1390
+                }
1391
+
1385 1392
                 try {
1386 1393
                     room.broadcastEndpointMessage({
1387 1394
                         type: this.commands.defaults.CONNECTION_QUALITY,
@@ -1394,10 +1401,15 @@ export default {
1394 1401
         room.on(ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
1395 1402
             (participant, payload) => {
1396 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 1411
                         break;
1412
+                    }
1401 1413
                     default:
1402 1414
                         console.warn("Unknown datachannel message", payload);
1403 1415
                 }

+ 9
- 0
modules/UI/UI.js Прегледај датотеку

@@ -779,6 +779,15 @@ UI.getRemoteVideoType = function (jid) {
779 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 791
 UI.connectionIndicatorShowMore = function(id) {
783 792
     VideoLayout.showMore(id);
784 793
 };

+ 10
- 0
modules/UI/videolayout/VideoLayout.js Прегледај датотеку

@@ -327,6 +327,16 @@ var VideoLayout = {
327 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 340
     isPinned (id) {
331 341
         return (pinnedId) ? (id === pinnedId) : false;
332 342
     },

+ 107
- 23
modules/connectionquality/connectionquality.js Прегледај датотеку

@@ -1,3 +1,4 @@
1
+/* global config */
1 2
 import EventEmitter from "events";
2 3
 
3 4
 import CQEvents from "../../service/connectionquality/CQEvents";
@@ -35,6 +36,58 @@ function calculateQuality(newVal, oldVal) {
35 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 91
 export default {
39 92
     /**
40 93
      * Updates the local statistics
@@ -42,15 +95,28 @@ export default {
42 95
      * @param dontUpdateLocalConnectionQuality {boolean} if true -
43 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,23 +134,41 @@ export default {
68 134
      * @param id the id associated with the statistics
69 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
     /**

Loading…
Откажи
Сачувај