浏览代码

feat: Use the new bridge signaling format.

Translate the 'LastNChangedEvent', 'SelectedEndpointsChangedEvent' and 'ReceiverVideoConstraint' messages into the new 'ReceiverVideoConstraints' message that invokes the new bandwidth allocation algorithm in the bridge that is described here - https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md. useNewBandwidthAllocationStrategy=true in config.js will invoke the translation in the client.
dev1
Jaya Allamsetty 4 年前
父节点
当前提交
beaff3dd02
没有帐户链接到提交者的电子邮件
共有 3 个文件被更改,包括 222 次插入37 次删除
  1. 13
    0
      modules/RTC/BridgeChannel.js
  2. 41
    34
      modules/RTC/RTC.js
  3. 168
    3
      modules/qualitycontrol/ReceiveVideoController.js

+ 13
- 0
modules/RTC/BridgeChannel.js 查看文件

@@ -234,6 +234,19 @@ export default class BridgeChannel {
234 234
         });
235 235
     }
236 236
 
237
+    /**
238
+     * Sends a 'ReceiverVideoConstraints' message via the bridge channel.
239
+     *
240
+     * @param {ReceiverVideoConstraints} constraints video constraints.
241
+     */
242
+    sendNewReceiverVideoConstraintsMessage(constraints) {
243
+        logger.log(`Sending ReceiverVideoConstraints with ${JSON.stringify(constraints)}`);
244
+        this._send({
245
+            colibriClass: 'ReceiverVideoConstraints',
246
+            ...constraints
247
+        });
248
+    }
249
+
237 250
     /**
238 251
      * Set events on the given RTCDataChannel or WebSocket instance.
239 252
      */

+ 41
- 34
modules/RTC/RTC.js 查看文件

@@ -257,49 +257,42 @@ export default class RTC extends Listenable {
257 257
      * @param {string} [wsUrl] WebSocket URL.
258 258
      */
259 259
     initializeBridgeChannel(peerconnection, wsUrl) {
260
-        this._channel = new BridgeChannel(
261
-            peerconnection, wsUrl, this.eventEmitter);
260
+        this._channel = new BridgeChannel(peerconnection, wsUrl, this.eventEmitter);
262 261
 
263 262
         this._channelOpenListener = () => {
264
-            // When the channel becomes available, tell the bridge about
265
-            // video selections so that it can do adaptive simulcast,
266
-            // we want the notification to trigger even if userJid
267
-            // is undefined, or null.
268
-            try {
269
-                this._channel.sendSelectedEndpointsMessage(
270
-                    this._selectedEndpoints);
271
-
272
-                if (typeof this._maxFrameHeight !== 'undefined') {
273
-                    this._channel.sendReceiverVideoConstraintMessage(
274
-                        this._maxFrameHeight);
263
+            // When the channel becomes available, tell the bridge about video selections so that it can do adaptive
264
+            // simulcast, we want the notification to trigger even if userJid is undefined, or null.
265
+            if (this._receiverVideoConstraints) {
266
+                try {
267
+                    this._channel.sendNewReceiverVideoConstraintsMessage(this._receiverVideoConstraints);
268
+                } catch (error) {
269
+                    GlobalOnErrorHandler.callErrorHandler(error);
270
+                    logger.error(`Cannot send ReceiverVideoConstraints(
271
+                        ${JSON.stringify(this._receiverVideoConstraints)}) endpoint message`, error);
272
+                }
273
+            } else {
274
+                try {
275
+                    this._channel.sendSelectedEndpointsMessage(this._selectedEndpoints);
276
+                    if (typeof this._maxFrameHeight !== 'undefined') {
277
+                        this._channel.sendReceiverVideoConstraintMessage(this._maxFrameHeight);
278
+                    }
279
+                    if (this._lastN !== -1) {
280
+                        this._channel.sendSetLastNMessage(this._lastN);
281
+                    }
282
+                } catch (error) {
283
+                    GlobalOnErrorHandler.callErrorHandler(error);
284
+                    logger.error(`Cannot send selected(${this._selectedEndpoint}), lastN(${this._lastN}),`
285
+                        + ` frameHeight(${this._maxFrameHeight}) endpoint message`, error);
275 286
                 }
276
-            } catch (error) {
277
-                GlobalOnErrorHandler.callErrorHandler(error);
278
-                logger.error(
279
-                    `Cannot send selected(${this._selectedEndpoint})`
280
-                    + `frameHeight(${this._maxFrameHeight}) endpoint message`,
281
-                    error);
282 287
             }
283 288
 
284
-            this.removeListener(RTCEvents.DATA_CHANNEL_OPEN,
285
-                this._channelOpenListener);
289
+            this.removeListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);
286 290
             this._channelOpenListener = null;
287
-
288
-            // If setLastN was invoked before the bridge channel completed
289
-            // opening, apply the specified value now that the channel
290
-            // is open. NOTE that -1 is the default value assumed by both
291
-            // RTC module and the JVB.
292
-            if (this._lastN !== -1) {
293
-                this._channel.sendSetLastNMessage(this._lastN);
294
-            }
295 291
         };
296
-
297
-        this.addListener(RTCEvents.DATA_CHANNEL_OPEN,
298
-            this._channelOpenListener);
292
+        this.addListener(RTCEvents.DATA_CHANNEL_OPEN, this._channelOpenListener);
299 293
 
300 294
         // Add Last N change listener.
301
-        this.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
302
-            this._lastNChangeListener);
295
+        this.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED, this._lastNChangeListener);
303 296
     }
304 297
 
305 298
     /**
@@ -358,6 +351,20 @@ export default class RTC extends Listenable {
358 351
         }
359 352
     }
360 353
 
354
+    /**
355
+     * Sets the receiver video constraints that determine how bitrate is allocated to each of the video streams
356
+     * requested from the bridge. The constraints are cached and sent through the bridge channel once the channel
357
+     * is established.
358
+     * @param {*} constraints
359
+     */
360
+    setNewReceiverVideoConstraints(constraints) {
361
+        this._receiverVideoConstraints = constraints;
362
+
363
+        if (this._channel && this._channel.isOpen()) {
364
+            this._channel.sendNewReceiverVideoConstraintsMessage(constraints);
365
+        }
366
+    }
367
+
361 368
     /**
362 369
      * Sets the maximum video size the local participant should receive from
363 370
      * remote participants. Will cache the value and send it through the channel

+ 168
- 3
modules/qualitycontrol/ReceiveVideoController.js 查看文件

@@ -1,6 +1,140 @@
1
+import { getLogger } from 'jitsi-meet-logger';
1 2
 
2 3
 import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
3 4
 
5
+const logger = getLogger(__filename);
6
+const MAX_HEIGHT_ONSTAGE = 2160;
7
+const MAX_HEIGHT_THUMBNAIL = 180;
8
+const LASTN_UNLIMITED = -1;
9
+
10
+/**
11
+ * This class translates the legacy signaling format between the client and the bridge (that affects bandwidth
12
+ * allocation) to the new format described here https://github.com/jitsi/jitsi-videobridge/blob/master/doc/allocation.md
13
+ */
14
+export class ReceiverVideoConstraints {
15
+    /**
16
+     * Creates a new instance.
17
+     */
18
+    constructor() {
19
+        // Default constraints used for endpoints that are not explicitly included in constraints.
20
+        // These constraints are used for endpoints that are thumbnails in the stage view.
21
+        this._defaultConstraints = { 'maxHeight': MAX_HEIGHT_THUMBNAIL };
22
+
23
+        // The number of videos requested from the bridge.
24
+        this._lastN = LASTN_UNLIMITED;
25
+
26
+        // The number representing the maximum video height the local client should receive from the bridge.
27
+        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;
28
+
29
+        // The endpoint IDs of the participants that are currently selected.
30
+        this._selectedEndpoints = [];
31
+
32
+        this._receiverVideoConstraints = {
33
+            constraints: {},
34
+            defaultConstraints: this.defaultConstraints,
35
+            lastN: this._lastN,
36
+            onStageEndpoints: [],
37
+            selectedEndpoints: this._selectedEndpoints
38
+        };
39
+    }
40
+
41
+    /**
42
+     * Returns the receiver video constraints that need to be sent on the bridge channel.
43
+     */
44
+    get constraints() {
45
+        this._receiverVideoConstraints.lastN = this._lastN;
46
+
47
+        if (!this._selectedEndpoints.length) {
48
+            return this._receiverVideoConstraints;
49
+        }
50
+
51
+        // The client is assumed to be in TileView if it has selected more than one endpoint, otherwise it is
52
+        // assumed to be in StageView.
53
+        this._receiverVideoConstraints.constraints = {};
54
+        if (this._selectedEndpoints.length > 1) {
55
+            /**
56
+             * Tile view.
57
+             * Only the default constraints are specified here along with lastN (if it is set).
58
+             * {
59
+             *  'colibriClass': 'ReceiverVideoConstraints',
60
+             *  'defaultConstraints': { 'maxHeight': 360 }
61
+             * }
62
+             */
63
+            this._receiverVideoConstraints.defaultConstraints = { 'maxHeight': this._maxFrameHeight };
64
+            this._receiverVideoConstraints.onStageEndpoints = [];
65
+            this._receiverVideoConstraints.selectedEndpoints = [];
66
+        } else {
67
+            /**
68
+             * Stage view.
69
+             * The participant on stage is specified in onStageEndpoints and a higher maxHeight is specified
70
+             * for that endpoint while a default maxHeight of 180 is applied to all the other endpoints.
71
+             * {
72
+             *  'colibriClass': 'ReceiverVideoConstraints',
73
+             *  'onStageEndpoints': ['A'],
74
+             *  'defaultConstraints': { 'maxHeight':  180 },
75
+             *  'constraints': {
76
+             *      'A': { 'maxHeight': 720 }
77
+             *   }
78
+             * }
79
+             */
80
+            this._receiverVideoConstraints.constraints[this._selectedEndpoints[0]] = {
81
+                'maxHeight': this._maxFrameHeight
82
+            };
83
+            this._receiverVideoConstraints.defaultConstraints = this._defaultConstraints;
84
+            this._receiverVideoConstraints.onStageEndpoints = this._selectedEndpoints;
85
+            this._receiverVideoConstraints.selectedEndpoints = [];
86
+        }
87
+
88
+        return this._receiverVideoConstraints;
89
+    }
90
+
91
+    /**
92
+     * Updates the lastN field of the ReceiverVideoConstraints sent to the bridge.
93
+     *
94
+     * @param {number} value
95
+     * @returns {boolean} Returns true if the the value has been updated, false otherwise.
96
+     */
97
+    updateLastN(value) {
98
+        const changed = this._lastN !== value;
99
+
100
+        if (changed) {
101
+            this._lastN = value;
102
+            logger.debug(`Updating ReceiverVideoConstraints lastN(${value})`);
103
+        }
104
+
105
+        return changed;
106
+    }
107
+
108
+    /**
109
+     * Updates the resolution (height requested) in the contraints field of the ReceiverVideoConstraints
110
+     * sent to the bridge.
111
+     *
112
+     * @param {number} maxFrameHeight
113
+     * @requires {boolean} Returns true if the the value has been updated, false otherwise.
114
+     */
115
+    updateReceiveResolution(maxFrameHeight) {
116
+        const changed = this._maxFrameHeight !== maxFrameHeight;
117
+
118
+        if (changed) {
119
+            this._maxFrameHeight = maxFrameHeight;
120
+            logger.debug(`Updating receive maxFrameHeight: ${maxFrameHeight}`);
121
+        }
122
+
123
+        return changed;
124
+    }
125
+
126
+    /**
127
+     * Updates the list of selected endpoints.
128
+     *
129
+     * @param {Array<string>} ids
130
+     * @returns {void}
131
+     */
132
+    updateSelectedEndpoints(ids) {
133
+        logger.debug(`Updating selected endpoints: ${JSON.stringify(ids)}`);
134
+        this._selectedEndpoints = ids;
135
+    }
136
+}
137
+
4 138
 /**
5 139
  * This class manages the receive video contraints for a given {@link JitsiConference}. These constraints are
6 140
  * determined by the application based on how the remote video streams need to be displayed. This class is responsible
@@ -18,11 +152,16 @@ export class ReceiveVideoController {
18 152
         this._conference = conference;
19 153
         this._rtc = rtc;
20 154
 
155
+        // Translate the legacy bridge channel signaling format to the new format.
156
+        this._receiverVideoConstraints = conference.options?.config?.useNewBandwidthAllocationStrategy
157
+            ? new ReceiverVideoConstraints()
158
+            : undefined;
159
+
21 160
         // The number of videos requested from the bridge, -1 represents unlimited or all available videos.
22
-        this._lastN = -1;
161
+        this._lastN = LASTN_UNLIMITED;
23 162
 
24 163
         // The number representing the maximum video height the local client should receive from the bridge.
25
-        this._maxFrameHeight = 2160;
164
+        this._maxFrameHeight = MAX_HEIGHT_ONSTAGE;
26 165
 
27 166
         // The endpoint IDs of the participants that are currently selected.
28 167
         this._selectedEndpoints = [];
@@ -53,6 +192,16 @@ export class ReceiveVideoController {
53 192
      */
54 193
     selectEndpoints(ids) {
55 194
         this._selectedEndpoints = ids;
195
+
196
+        if (this._receiverVideoConstraints) {
197
+            const remoteEndpointIds = ids.filter(id => id !== this._conference.myUserId());
198
+
199
+            // Filter out the local endpointId from the list of selected endpoints.
200
+            remoteEndpointIds.length && this._receiverVideoConstraints.updateSelectedEndpoints(remoteEndpointIds);
201
+            this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
202
+
203
+            return;
204
+        }
56 205
         this._rtc.selectEndpoints(ids);
57 206
     }
58 207
 
@@ -66,6 +215,15 @@ export class ReceiveVideoController {
66 215
     setLastN(value) {
67 216
         if (this._lastN !== value) {
68 217
             this._lastN = value;
218
+
219
+            if (this._receiverVideoConstraints) {
220
+                const lastNUpdated = this._receiverVideoConstraints.updateLastN(value);
221
+
222
+                // Send out the message on the bridge channel if lastN was updated.
223
+                lastNUpdated && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
224
+
225
+                return;
226
+            }
69 227
             this._rtc.setLastN(value);
70 228
         }
71 229
     }
@@ -80,7 +238,14 @@ export class ReceiveVideoController {
80 238
         this._maxFrameHeight = maxFrameHeight;
81 239
 
82 240
         for (const session of this._conference._getMediaSessions()) {
83
-            maxFrameHeight && session.setReceiverVideoConstraint(maxFrameHeight);
241
+            if (session.isP2P || !this._receiverVideoConstraints) {
242
+                maxFrameHeight && session.setReceiverVideoConstraint(maxFrameHeight);
243
+            } else {
244
+                const resolutionUpdated = this._receiverVideoConstraints.updateReceiveResolution(maxFrameHeight);
245
+
246
+                resolutionUpdated
247
+                    && this._rtc.setNewReceiverVideoConstraints(this._receiverVideoConstraints.constraints);
248
+            }
84 249
         }
85 250
     }
86 251
 }

正在加载...
取消
保存