瀏覽代碼

feat(chrome|safari): stop the video for maxFrameHeight 0

master
paweldomas 4 年之前
父節點
當前提交
a73de37b2b

+ 16
- 6
modules/RTC/TraceablePeerConnection.js 查看文件

@@ -2221,17 +2221,22 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
2221 2221
  * successful and rejected otherwise.
2222 2222
  */
2223 2223
 TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeight = null) {
2224
+    if (frameHeight < 0) {
2225
+        throw new Error(`Invalid frameHeight: ${frameHeight}`);
2226
+    }
2227
+
2224 2228
     // XXX: This is not yet supported on mobile.
2225 2229
     if (browser.isReactNative()) {
2226 2230
         return Promise.resolve();
2227 2231
     }
2228 2232
 
2229
-    const newHeight = frameHeight || this.senderVideoMaxHeight;
2233
+    // Need to explicitly check for null as 0 is falsy, but a valid value
2234
+    const newHeight = frameHeight === null ? this.senderVideoMaxHeight : frameHeight;
2230 2235
 
2231 2236
     this.senderVideoMaxHeight = newHeight;
2232
-    if (!newHeight) {
2233
-        return Promise.resolve();
2234
-    }
2237
+
2238
+    logger.log(`${this} senderVideoMaxHeight: ${newHeight}`);
2239
+
2235 2240
     const localVideoTrack = this.getLocalVideoTrack();
2236 2241
 
2237 2242
     if (!localVideoTrack || localVideoTrack.isMuted() || localVideoTrack.videoType !== VideoType.CAMERA) {
@@ -2247,7 +2252,6 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2247 2252
     if (!parameters || !parameters.encodings || !parameters.encodings.length) {
2248 2253
         return Promise.reject(new Error('RTCRtpSendParameters not found for local video track'));
2249 2254
     }
2250
-    logger.info(`Setting max height of ${newHeight} on local video`);
2251 2255
 
2252 2256
     if (this.isSimulcastOn()) {
2253 2257
         // Determine the encodings that need to stay enabled based on the
@@ -2260,10 +2264,16 @@ TraceablePeerConnection.prototype.setSenderVideoConstraint = function(frameHeigh
2260 2264
                 parameters.encodings[encoding].active = encodingsEnabledState[encoding];
2261 2265
             }
2262 2266
         }
2263
-    } else if (localVideoTrack.resolution > newHeight) {
2267
+    } else if (newHeight > 0) {
2264 2268
         parameters.encodings[0].scaleResolutionDownBy = Math.floor(localVideoTrack.resolution / newHeight);
2269
+        parameters.encodings[0].active = true;
2270
+    } else {
2271
+        parameters.encodings[0].scaleResolutionDownBy = undefined;
2272
+        parameters.encodings[0].active = false;
2265 2273
     }
2266 2274
 
2275
+    logger.info(`${this} setting max height of ${newHeight}, encodings: ${JSON.stringify(parameters.encodings)}`);
2276
+
2267 2277
     return videoSender.setParameters(parameters).then(() => {
2268 2278
         localVideoTrack.maxEnabledResolution = newHeight;
2269 2279
         this.eventEmitter.emit(RTCEvents.LOCAL_TRACK_MAX_ENABLED_RESOLUTION_CHANGED, localVideoTrack);

+ 6
- 8
modules/qualitycontrol/QualityController.js 查看文件

@@ -62,12 +62,10 @@ export class QualityController {
62 62
         const sendMaxFrameHeight = this.selectSendMaxFrameHeight();
63 63
         const promises = [];
64 64
 
65
-        if (!sendMaxFrameHeight) {
66
-            return Promise.resolve();
67
-        }
68
-
69
-        for (const session of this.conference._getMediaSessions()) {
70
-            promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight));
65
+        if (sendMaxFrameHeight >= 0) {
66
+            for (const session of this.conference._getMediaSessions()) {
67
+                promises.push(session.setSenderVideoConstraint(sendMaxFrameHeight));
68
+            }
71 69
         }
72 70
 
73 71
         return Promise.all(promises);
@@ -83,9 +81,9 @@ export class QualityController {
83 81
         const activeMediaSession = this.conference._getActiveMediaSession();
84 82
         const remoteRecvMaxFrameHeight = activeMediaSession && activeMediaSession.getRemoteRecvMaxFrameHeight();
85 83
 
86
-        if (this.preferredSendMaxFrameHeight && remoteRecvMaxFrameHeight) {
84
+        if (this.preferredSendMaxFrameHeight >= 0 && remoteRecvMaxFrameHeight >= 0) {
87 85
             return Math.min(this.preferredSendMaxFrameHeight, remoteRecvMaxFrameHeight);
88
-        } else if (remoteRecvMaxFrameHeight) {
86
+        } else if (remoteRecvMaxFrameHeight >= 0) {
89 87
             return remoteRecvMaxFrameHeight;
90 88
         }
91 89
 

+ 134
- 0
modules/qualitycontrol/QualityController.spec.js 查看文件

@@ -0,0 +1,134 @@
1
+import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
2
+import Listenable from '../util/Listenable';
3
+import MediaSessionEvents from '../xmpp/MediaSessionEvents';
4
+
5
+import { QualityController } from './QualityController';
6
+
7
+// JSDocs disabled for Mock classes to avoid duplication - check on the original classes for info.
8
+/* eslint-disable require-jsdoc */
9
+/**
10
+ * A mock JingleSessionPC impl that fit the needs of the QualityController module.
11
+ * Should a generic, shared one exist in the future this test file should switch to use it too.
12
+ */
13
+class MockJingleSessionPC extends Listenable {
14
+    constructor() {
15
+        super();
16
+        this._remoteRecvMaxFrameHeight = undefined;
17
+        this.senderVideoConstraint = undefined;
18
+    }
19
+
20
+    getRemoteRecvMaxFrameHeight() {
21
+        return this._remoteRecvMaxFrameHeight;
22
+    }
23
+
24
+    // eslint-disable-next-line no-empty-function
25
+    setSenderVideoDegradationPreference() {
26
+
27
+    }
28
+
29
+    // eslint-disable-next-line no-empty-function
30
+    setSenderMaxBitrates() {
31
+
32
+    }
33
+
34
+    setSenderVideoConstraint(senderVideoConstraint) {
35
+        this.senderVideoConstraint = senderVideoConstraint;
36
+    }
37
+
38
+    setRemoteRecvMaxFrameHeight(remoteRecvMaxFrameHeight) {
39
+        this._remoteRecvMaxFrameHeight = remoteRecvMaxFrameHeight;
40
+        this.eventEmitter.emit(
41
+            MediaSessionEvents.REMOTE_VIDEO_CONSTRAINTS_CHANGED,
42
+            this);
43
+    }
44
+}
45
+
46
+/**
47
+ * Mock conference for the purpose of this test file.
48
+ */
49
+class MockConference extends Listenable {
50
+    /**
51
+     * A constructor...
52
+     */
53
+    constructor() {
54
+        super();
55
+        this.options = {
56
+            config: { }
57
+        };
58
+        this.activeMediaSession = undefined;
59
+        this.mediaSessions = [];
60
+    }
61
+
62
+    addMediaSession(mediaSession) {
63
+        this.mediaSessions.push(mediaSession);
64
+
65
+        this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, mediaSession);
66
+    }
67
+
68
+    setActiveMediaSession(mediaSession) {
69
+        if (this.mediaSessions.indexOf(mediaSession) === -1) {
70
+            throw new Error('Given session is not part of this conference');
71
+        }
72
+
73
+        this.activeMediaSession = mediaSession;
74
+
75
+        this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED, this.activeMediaSession);
76
+    }
77
+
78
+    _getActiveMediaSession() {
79
+        return this.activeMediaSession;
80
+    }
81
+
82
+    _getMediaSessions() {
83
+        return this.mediaSessions;
84
+    }
85
+}
86
+/* eslint-enable require-jsdoc */
87
+
88
+describe('QualityController', () => {
89
+    let conference;
90
+    let qualityController;
91
+    let jvbConnection;
92
+    let p2pConnection;
93
+
94
+    beforeEach(() => {
95
+        conference = new MockConference();
96
+        qualityController = new QualityController(conference);
97
+        jvbConnection = new MockJingleSessionPC();
98
+        p2pConnection = new MockJingleSessionPC();
99
+
100
+        conference.addMediaSession(jvbConnection);
101
+        conference.addMediaSession(p2pConnection);
102
+    });
103
+    describe('handles 0 as receiver/sender video constraint', () => {
104
+        it('0 if it\'s the active sessions\'s remote recv constraint', () => {
105
+            jvbConnection.setRemoteRecvMaxFrameHeight(0);
106
+            p2pConnection.setRemoteRecvMaxFrameHeight(720);
107
+
108
+            conference.setActiveMediaSession(jvbConnection);
109
+
110
+            expect(jvbConnection.senderVideoConstraint).toBe(0);
111
+            expect(p2pConnection.senderVideoConstraint).toBe(0);
112
+        });
113
+        it('720 if 0 is set on the non-active session', () => {
114
+            jvbConnection.setRemoteRecvMaxFrameHeight(0);
115
+            p2pConnection.setRemoteRecvMaxFrameHeight(720);
116
+
117
+            conference.setActiveMediaSession(p2pConnection);
118
+
119
+            expect(jvbConnection.senderVideoConstraint).toBe(720);
120
+            expect(p2pConnection.senderVideoConstraint).toBe(720);
121
+        });
122
+        it('0 if it\'s the local send preference while remote are 720', () => {
123
+            conference.setActiveMediaSession(p2pConnection);
124
+
125
+            jvbConnection.setRemoteRecvMaxFrameHeight(720);
126
+            p2pConnection.setRemoteRecvMaxFrameHeight(720);
127
+
128
+            qualityController.setPreferredSendMaxFrameHeight(0);
129
+
130
+            expect(jvbConnection.senderVideoConstraint).toBe(0);
131
+            expect(p2pConnection.senderVideoConstraint).toBe(0);
132
+        });
133
+    });
134
+});

Loading…
取消
儲存