소스 검색

fix(codec-selection): Codec selection fixes.

1. Checks peer's preferred codec in p2p case. Mobile and web have different preferred codecs.
2. Log an error message when the preferred codec is not offered by JVB.
3. Clean up code related to deprecated config.js settings 'preferH264' and 'disableH264'.
4. Refactor the codec selection logic so that correct codec is picked.
tags/v0.0.2
Jaya Allamsetty 2 년 전
부모
커밋
2d4cd935cb
4개의 변경된 파일85개의 추가작업 그리고 88개의 파일을 삭제
  1. 20
    11
      JitsiConference.js
  2. 59
    68
      modules/RTC/CodecSelection.js
  3. 2
    0
      modules/sdp/SDPUtil.js
  4. 4
    9
      modules/xmpp/JingleSessionPC.js

+ 20
- 11
JitsiConference.js 파일 보기

80
  */
80
  */
81
 const JINGLE_SI_TIMEOUT = 5000;
81
 const JINGLE_SI_TIMEOUT = 5000;
82
 
82
 
83
+/**
84
+ * Checks if a given string is a valid video codec mime type.
85
+ *
86
+ * @param {string} codec the codec string that needs to be validated.
87
+ * @returns {CodecMimeType|null} mime type if valid, null otherwise.
88
+ * @private
89
+ */
90
+function _getCodecMimeType(codec) {
91
+    if (typeof codec === 'string') {
92
+        return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());
93
+    }
94
+
95
+    return null;
96
+}
97
+
83
 /**
98
 /**
84
  * Creates a JitsiConference object with the given name and properties.
99
  * Creates a JitsiConference object with the given name and properties.
85
  * Note: this constructor is not a part of the public API (objects should be
100
  * Note: this constructor is not a part of the public API (objects should be
355
     const { config } = this.options;
370
     const { config } = this.options;
356
 
371
 
357
     // Get the codec preference settings from config.js.
372
     // Get the codec preference settings from config.js.
358
-    // 'preferH264' and 'disableH264' settings have been deprecated for a while,
359
-    // 'preferredCodec' and 'disabledCodec' will have precedence over them.
360
     const codecSettings = {
373
     const codecSettings = {
361
-        disabledCodec: config.videoQuality
362
-            ? config.videoQuality.disabledCodec
363
-            : config.p2p && config.p2p.disableH264 && CodecMimeType.H264,
364
-        enforcePreferredCodec: config.videoQuality && config.videoQuality.enforcePreferredCodec,
365
-        jvbCodec: (config.videoQuality && config.videoQuality.preferredCodec)
366
-            || (config.preferH264 && CodecMimeType.H264),
367
-        p2pCodec: config.p2p
368
-            ? config.p2p.preferredCodec || (config.p2p.preferH264 && CodecMimeType.H264)
369
-            : CodecMimeType.VP8
374
+        jvbDisabledCodec: _getCodecMimeType(config.videoQuality?.disabledCodec),
375
+        p2pDisabledCodec: _getCodecMimeType(config.p2p?.disabledCodec),
376
+        enforcePreferredCodec: config.videoQuality?.enforcePreferredCodec,
377
+        jvbPreferredCodec: _getCodecMimeType(config.videoQuality?.preferredCodec),
378
+        p2pPreferredCodec: _getCodecMimeType(config.p2p?.preferredCodec)
370
     };
379
     };
371
 
380
 
372
     this.codecSelection = new CodecSelection(this, codecSettings);
381
     this.codecSelection = new CodecSelection(this, codecSettings);

+ 59
- 68
modules/RTC/CodecSelection.js 파일 보기

32
     constructor(conference, options) {
32
     constructor(conference, options) {
33
         this.conference = conference;
33
         this.conference = conference;
34
         this.options = options;
34
         this.options = options;
35
-
36
-        // VP8 cannot be disabled and it will be the default codec when no preference is set.
37
-        this.disabledCodec = options.disabledCodec === CodecMimeType.VP8
38
-            ? undefined
39
-            : this._getCodecMimeType(options.disabledCodec);
40
-
41
-        // Check if the codec values passed are valid.
42
-        const jvbCodec = this._getCodecMimeType(options.jvbCodec);
43
-        const p2pCodec = this._getCodecMimeType(options.p2pCodec);
44
-
45
-        this.jvbPreferredCodec = jvbCodec && this._isCodecSupported(jvbCodec) ? jvbCodec : CodecMimeType.VP8;
46
-        this.p2pPreferredCodec = p2pCodec && this._isCodecSupported(p2pCodec) ? p2pCodec : CodecMimeType.VP8;
47
-        logger.debug(`Codec preferences for the conference are JVB: ${this.jvbPreferredCodec},
48
-            P2P: ${this.p2pPreferredCodec}`);
49
-
50
-        if (this.jvbPreferredCodec === CodecMimeType.VP9 && !browser.supportsVP9()) {
51
-            this.jvbPreferredCodec = CodecMimeType.VP8;
52
-        }
35
+        this.enforcePreferredCodec = options.enforcePreferredCodec;
36
+
37
+        // VP8 cannot be disabled since it the default codec.
38
+        this.p2pDisabledCodec = options.p2pDisabledCodec !== CodecMimeType.VP8
39
+            && this._isCodecSupported(options.p2pDisabledCodec)
40
+            && options.p2pDisabledCodec;
41
+        this.jvbDisabledCodec = options.jvbDisabledCodec !== CodecMimeType.VP8
42
+            && this._isCodecSupported(options.jvbDisabledCodec)
43
+            && options.jvbDisabledCodec;
44
+
45
+        // Determine the preferred codecs.
46
+        this.p2pPreferredCodec = this._isCodecSupported(options.p2pPreferredCodec)
47
+            && options.p2pPreferredCodec !== options.p2pDisabledCodec
48
+            ? options.p2pPreferredCodec
49
+            : CodecMimeType.VP8;
50
+        this.jvbPreferredCodec = this._isCodecSupported(options.jvbPreferredCodec)
51
+            && options.jvbPreferredCodec !== options.jvbDisabledCodec
52
+            ? options.jvbPreferredCodec
53
+            : CodecMimeType.VP8;
54
+
55
+        logger.debug(`Codec preferences for the conference are JVB: preferred=${this.jvbPreferredCodec},`
56
+            + `disabled=${this.jvbDisabledCodec} P2P: preferred=${this.p2pPreferredCodec},`
57
+            + `disabled=${this.p2pDisabledCodec}`);
53
 
58
 
54
         this.conference.on(
59
         this.conference.on(
55
             JitsiConferenceEvents.USER_JOINED,
60
             JitsiConferenceEvents.USER_JOINED,
59
             () => this._selectPreferredCodec());
64
             () => this._selectPreferredCodec());
60
         this.conference.on(
65
         this.conference.on(
61
             JitsiConferenceEvents._MEDIA_SESSION_STARTED,
66
             JitsiConferenceEvents._MEDIA_SESSION_STARTED,
62
-            session => this._onMediaSessionStarted(session));
63
-    }
64
-
65
-    /**
66
-     * Checks if a given string is a valid video codec mime type.
67
-     *
68
-     * @param {string} codec the codec string that needs to be validated.
69
-     * @returns {CodecMimeType|null} mime type if valid, null otherwise.
70
-     * @private
71
-     */
72
-    _getCodecMimeType(codec) {
73
-        if (typeof codec === 'string') {
74
-            return Object.values(CodecMimeType).find(value => value === codec.toLowerCase());
75
-        }
76
-
77
-        return null;
67
+            session => this._selectPreferredCodec(session));
78
     }
68
     }
79
 
69
 
80
     /**
70
     /**
85
      * @private
75
      * @private
86
      */
76
      */
87
     _isCodecSupported(preferredCodec) {
77
     _isCodecSupported(preferredCodec) {
78
+        if (!preferredCodec) {
79
+            return false;
80
+        }
81
+
82
+        if (preferredCodec === CodecMimeType.VP9 && !this.enforcePreferredCodec && !browser.supportsVP9()) {
83
+            return false;
84
+        }
85
+
88
         // Skip the check on FF because it does not support the getCapabilities API.
86
         // Skip the check on FF because it does not support the getCapabilities API.
89
-        // It is safe to assume both of them support all the codecs supported by Chrome.
87
+        // It is safe to assume that Firefox supports all the codecs supported by Chrome.
90
         if (browser.isFirefox()) {
88
         if (browser.isFirefox()) {
91
             return true;
89
             return true;
92
         }
90
         }
98
     }
96
     }
99
 
97
 
100
     /**
98
     /**
101
-     * Handles the {@link JitsiConferenceEvents._MEDIA_SESSION_STARTED} event. Codecs need to be
102
-     * configured on the media session that is newly created.
103
-     *
104
-     * @param {JingleSessionPC} mediaSession media session that started.
105
-     * @returns {void}
106
-     * @private
107
-     */
108
-    _onMediaSessionStarted(mediaSession) {
109
-        const preferredCodec = mediaSession.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;
110
-        const disabledCodec = this.disabledCodec && this._isCodecSupported(this.disabledCodec)
111
-            ? this.disabledCodec
112
-            : null;
113
-
114
-        this._selectPreferredCodec(mediaSession, preferredCodec, disabledCodec);
115
-    }
116
-
117
-    /**
118
-     * Sets the codec on the media session based on the preferred codec setting and the supported codecs
99
+     * Sets the codec on the media session based on the preferred/disabled codec setting and the supported codecs
119
      * published by the remote participants in their presence.
100
      * published by the remote participants in their presence.
120
      *
101
      *
121
      * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.
102
      * @param {JingleSessionPC} mediaSession session for which the codec selection has to be made.
122
-     * @param {CodecMimeType} preferredCodec preferred codec.
123
-     * @param {CodecMimeType} disabledCodec codec that needs to be disabled.
124
      */
103
      */
125
-    _selectPreferredCodec(mediaSession = null, preferredCodec = null, disabledCodec = null) {
104
+    _selectPreferredCodec(mediaSession) {
126
         const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;
105
         const session = mediaSession ? mediaSession : this.conference.jvbJingleSession;
127
-        const currentCodec = preferredCodec ? preferredCodec : this.jvbPreferredCodec;
128
-        let selectedCodec = currentCodec;
129
 
106
 
130
-        if (session && !session.isP2P && !this.options.enforcePreferredCodec) {
131
-            const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());
107
+        if (!session) {
108
+            return;
109
+        }
110
+        const preferredCodec = session.isP2P ? this.p2pPreferredCodec : this.jvbPreferredCodec;
111
+        const disabledCodec = session.isP2P ? this.p2pDisabledCodec : this.jvbDisabledCodec;
112
+        const currentCodec = session?.peerconnection.getConfiguredVideoCodec();
113
+        let selectedCodec = preferredCodec ?? currentCodec;
132
 
114
 
133
-            for (const remote of remoteParticipants) {
115
+        if (!this.enforcePreferredCodec) {
116
+            const remoteParticipants = this.conference.getParticipants().map(participant => participant.getId());
117
+            const remoteCodecs = remoteParticipants?.map(remote => {
134
                 const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);
118
                 const peerMediaInfo = session._signalingLayer.getPeerMediaInfo(remote, MediaType.VIDEO);
135
-                const peerCodec = peerMediaInfo?.codecType;
136
 
119
 
137
-                if (peerCodec
138
-                    && peerCodec !== currentCodec
139
-                    && (peerCodec !== CodecMimeType.VP9 || browser.supportsVP9())) {
140
-                    selectedCodec = peerCodec;
141
-                }
120
+                return peerMediaInfo?.codecType;
121
+            });
122
+
123
+            const nonPreferredCodecs = remoteCodecs.filter(codec => codec !== selectedCodec && codec !== disabledCodec);
124
+
125
+            // Find the fallback codec when there are endpoints in the call that don't have the same preferred codec
126
+            // set.
127
+            if (nonPreferredCodecs.length) {
128
+                // Always prefer VP8 as that is the default codec supported on all client types.
129
+                selectedCodec = nonPreferredCodecs.find(codec => codec === CodecMimeType.VP8)
130
+                    ?? nonPreferredCodecs.find(codec => this._isCodecSupported(codec));
142
             }
131
             }
143
         }
132
         }
144
-        session && session.setVideoCodecs(selectedCodec, disabledCodec);
133
+        if (selectedCodec !== currentCodec || disabledCodec) {
134
+            session.setVideoCodecs(selectedCodec, disabledCodec);
135
+        }
145
     }
136
     }
146
 
137
 
147
     /**
138
     /**

+ 2
- 0
modules/sdp/SDPUtil.js 파일 보기

645
                 payloadTypes.unshift(pt);
645
                 payloadTypes.unshift(pt);
646
             }
646
             }
647
             mline.payloads = payloadTypes.join(' ');
647
             mline.payloads = payloadTypes.join(' ');
648
+        } else {
649
+            logger.error(`No matching RTP payload type found for ${codecName}, failed to set preferred codecs`);
648
         }
650
         }
649
     },
651
     },
650
 
652
 

+ 4
- 9
modules/xmpp/JingleSessionPC.js 파일 보기

90
  * @property {Object} abTesting - A/B testing related options (ask George).
90
  * @property {Object} abTesting - A/B testing related options (ask George).
91
  * @property {boolean} abTesting.enableSuspendVideoTest - enables the suspend
91
  * @property {boolean} abTesting.enableSuspendVideoTest - enables the suspend
92
  * video test ?(ask George).
92
  * video test ?(ask George).
93
- * @property {boolean} disableH264 - Described in the config.js[1].
94
  * @property {boolean} disableRtx - Described in the config.js[1].
93
  * @property {boolean} disableRtx - Described in the config.js[1].
95
  * @property {boolean} disableSimulcast - Described in the config.js[1].
94
  * @property {boolean} disableSimulcast - Described in the config.js[1].
96
  * @property {boolean} enableInsertableStreams - Set to true when the insertable streams constraints is to be enabled
95
  * @property {boolean} enableInsertableStreams - Set to true when the insertable streams constraints is to be enabled
443
                 pcOptions.abtestSuspendVideo = abtestSuspendVideo;
442
                 pcOptions.abtestSuspendVideo = abtestSuspendVideo;
444
             }
443
             }
445
         } else {
444
         } else {
446
-            // H264 does not support simulcast, so it needs to be disabled.
445
+            // H264 scalability is not supported on jvb, so simulcast needs to be disabled when H264 is preferred.
447
             pcOptions.disableSimulcast
446
             pcOptions.disableSimulcast
448
-                = options.disableSimulcast
449
-                    || (options.preferH264 && !options.disableH264)
450
-                    || (options.videoQuality && options.videoQuality.preferredCodec === CodecMimeType.H264);
447
+                = options.disableSimulcast || options.videoQuality?.preferredCodec === CodecMimeType.H264;
451
 
448
 
452
             // Disable simulcast for low fps screenshare and enable it for high fps screenshare.
449
             // Disable simulcast for low fps screenshare and enable it for high fps screenshare.
453
             // testing.capScreenshareBitrate config.js setting has now been deprecated.
450
             // testing.capScreenshareBitrate config.js setting has now been deprecated.
1285
      * @param {CodecMimeType} disabled the codec that needs to be disabled.
1282
      * @param {CodecMimeType} disabled the codec that needs to be disabled.
1286
      */
1283
      */
1287
     setVideoCodecs(preferred = null, disabled = null) {
1284
     setVideoCodecs(preferred = null, disabled = null) {
1288
-        const current = this.peerconnection.getConfiguredVideoCodec();
1289
-
1290
-        if (this._assertNotEnded() && preferred !== current) {
1291
-            logger.info(`${this} Switching video codec from ${current} to ${preferred}`);
1285
+        if (this._assertNotEnded()) {
1286
+            logger.info(`${this} setVideoCodecs: preferred=${preferred}, disabled=${disabled}`);
1292
             this.peerconnection.setVideoCodecs(preferred, disabled);
1287
             this.peerconnection.setVideoCodecs(preferred, disabled);
1293
 
1288
 
1294
             // Initiate a renegotiate for the codec setting to take effect.
1289
             // Initiate a renegotiate for the codec setting to take effect.

Loading…
취소
저장