|
|
@@ -265,6 +265,12 @@ export default function TraceablePeerConnection(
|
|
265
|
265
|
browser.supportsCodecPreferences()
|
|
266
|
266
|
&& logger.info('Using RTCRtpTransceiver#setCodecPreferences for codec selection');
|
|
267
|
267
|
|
|
|
268
|
+ /**
|
|
|
269
|
+ * Flag used to indicate if the codecs are configured using the codec selection API without having the need to
|
|
|
270
|
+ * trigger a renegotiation for the change to be effective.
|
|
|
271
|
+ */
|
|
|
272
|
+ this._usesCodecSelectionAPI = this.options.usesCodecSelectionAPI;
|
|
|
273
|
+
|
|
268
|
274
|
/**
|
|
269
|
275
|
* Indicates whether an audio track has ever been added to the peer connection.
|
|
270
|
276
|
*/
|
|
|
@@ -807,8 +813,8 @@ TraceablePeerConnection.prototype.getTargetVideoBitrates = function() {
|
|
807
|
813
|
};
|
|
808
|
814
|
|
|
809
|
815
|
/**
|
|
810
|
|
- * Tries to find {@link JitsiTrack} for given SSRC number. It will search both
|
|
811
|
|
- * local and remote tracks bound to this instance.
|
|
|
816
|
+ * Tries to find {@link JitsiTrack} for given SSRC number. It will search both local and remote tracks bound to this
|
|
|
817
|
+ * instance.
|
|
812
|
818
|
* @param {number} ssrc
|
|
813
|
819
|
* @return {JitsiTrack|null}
|
|
814
|
820
|
*/
|
|
|
@@ -817,7 +823,9 @@ TraceablePeerConnection.prototype.getTrackBySSRC = function(ssrc) {
|
|
817
|
823
|
throw new Error(`SSRC ${ssrc} is not a number`);
|
|
818
|
824
|
}
|
|
819
|
825
|
for (const localTrack of this.localTracks.values()) {
|
|
820
|
|
- if (this.getLocalSSRC(localTrack) === ssrc) {
|
|
|
826
|
+ const { ssrcs } = this.localSSRCs.get(localTrack.rtcId);
|
|
|
827
|
+
|
|
|
828
|
+ if (ssrcs.find(localSsrc => Number(localSsrc) === ssrc)) {
|
|
821
|
829
|
return localTrack;
|
|
822
|
830
|
}
|
|
823
|
831
|
}
|
|
|
@@ -1421,8 +1429,10 @@ TraceablePeerConnection.prototype._mungeCodecOrder = function(description) {
|
|
1421
|
1429
|
}
|
|
1422
|
1430
|
|
|
1423
|
1431
|
// Reorder the codecs based on the preferred settings.
|
|
1424
|
|
- for (const codec of this.codecSettings.codecList.slice().reverse()) {
|
|
1425
|
|
- SDPUtil.preferCodec(mLine, codec, this.isP2P);
|
|
|
1432
|
+ if (!this.usesCodecSelectionAPI()) {
|
|
|
1433
|
+ for (const codec of this.codecSettings.codecList.slice().reverse()) {
|
|
|
1434
|
+ SDPUtil.preferCodec(mLine, codec, this.isP2P);
|
|
|
1435
|
+ }
|
|
1426
|
1436
|
}
|
|
1427
|
1437
|
}
|
|
1428
|
1438
|
|
|
|
@@ -1593,6 +1603,15 @@ TraceablePeerConnection.prototype._assertTrackBelongs = function(
|
|
1593
|
1603
|
* video in the local SDP.
|
|
1594
|
1604
|
*/
|
|
1595
|
1605
|
TraceablePeerConnection.prototype.getConfiguredVideoCodec = function() {
|
|
|
1606
|
+ const localVideoTrack = this.getLocalVideoTracks()[0];
|
|
|
1607
|
+
|
|
|
1608
|
+ if (this.usesCodecSelectionAPI() && localVideoTrack) {
|
|
|
1609
|
+ const rtpSender = this.findSenderForTrack(localVideoTrack.getTrack());
|
|
|
1610
|
+ const { codecs } = rtpSender.getParameters();
|
|
|
1611
|
+
|
|
|
1612
|
+ return codecs[0].mimeType.split('/')[1].toLowerCase();
|
|
|
1613
|
+ }
|
|
|
1614
|
+
|
|
1596
|
1615
|
const sdp = this.peerconnection.remoteDescription?.sdp;
|
|
1597
|
1616
|
const defaultCodec = CodecMimeType.VP8;
|
|
1598
|
1617
|
|
|
|
@@ -1673,6 +1692,10 @@ TraceablePeerConnection.prototype.setVideoCodecs = function(codecList) {
|
|
1673
|
1692
|
}
|
|
1674
|
1693
|
|
|
1675
|
1694
|
this.codecSettings.codecList = codecList;
|
|
|
1695
|
+
|
|
|
1696
|
+ if (this.usesCodecSelectionAPI()) {
|
|
|
1697
|
+ this.configureVideoSenderEncodings();
|
|
|
1698
|
+ }
|
|
1676
|
1699
|
};
|
|
1677
|
1700
|
|
|
1678
|
1701
|
/**
|
|
|
@@ -1863,6 +1886,18 @@ TraceablePeerConnection.prototype.removeTrackFromPc = function(localTrack) {
|
|
1863
|
1886
|
return this.tpcUtils.replaceTrack(localTrack, null).then(() => false);
|
|
1864
|
1887
|
};
|
|
1865
|
1888
|
|
|
|
1889
|
+/**
|
|
|
1890
|
+ * Returns true if the codec selection API is used for switching between codecs for the video sources.
|
|
|
1891
|
+ *
|
|
|
1892
|
+ * @returns {boolean}
|
|
|
1893
|
+ */
|
|
|
1894
|
+TraceablePeerConnection.prototype.usesCodecSelectionAPI = function() {
|
|
|
1895
|
+ // Browser throws an error when H.264 is set on the encodings. Therefore, munge the SDP when H.264 needs to be
|
|
|
1896
|
+ // selected.
|
|
|
1897
|
+ // TODO: Remove this check when the above issue is fixed.
|
|
|
1898
|
+ return this._usesCodecSelectionAPI && this.codecSettings.codecList[0] !== CodecMimeType.H264;
|
|
|
1899
|
+};
|
|
|
1900
|
+
|
|
1866
|
1901
|
TraceablePeerConnection.prototype.createDataChannel = function(label, opts) {
|
|
1867
|
1902
|
this.trace('createDataChannel', label, opts);
|
|
1868
|
1903
|
|
|
|
@@ -1914,6 +1949,33 @@ TraceablePeerConnection.prototype._adjustRemoteMediaDirection = function(remoteD
|
|
1914
|
1949
|
});
|
|
1915
|
1950
|
};
|
|
1916
|
1951
|
|
|
|
1952
|
+/**
|
|
|
1953
|
+ * Returns the codec to be used for screenshare based on the supported codecs and the preferred codec requested
|
|
|
1954
|
+ * through config.js setting.
|
|
|
1955
|
+ *
|
|
|
1956
|
+ * @param {CodecMimeType} defaultCodec - the preferred codec for video tracks.
|
|
|
1957
|
+ * @returns {CodecMimeType}
|
|
|
1958
|
+ */
|
|
|
1959
|
+TraceablePeerConnection.prototype._getPreferredCodecForScreenshare = function(defaultCodec) {
|
|
|
1960
|
+ // Use the same codec for both camera and screenshare if the client doesn't support the codec selection API.
|
|
|
1961
|
+ if (!this.usesCodecSelectionAPI()) {
|
|
|
1962
|
+ return defaultCodec;
|
|
|
1963
|
+ }
|
|
|
1964
|
+
|
|
|
1965
|
+ const { screenshareCodec } = this.codecSettings;
|
|
|
1966
|
+
|
|
|
1967
|
+ if (screenshareCodec && this.codecSettings.codecList.find(c => c === screenshareCodec)) {
|
|
|
1968
|
+ return screenshareCodec;
|
|
|
1969
|
+ }
|
|
|
1970
|
+
|
|
|
1971
|
+ // Default to AV1 for screenshare if its supported and is not overriden through config.js.
|
|
|
1972
|
+ if (this.codecSettings.codecList.find(c => c === CodecMimeType.AV1)) {
|
|
|
1973
|
+ return CodecMimeType.AV1;
|
|
|
1974
|
+ }
|
|
|
1975
|
+
|
|
|
1976
|
+ return defaultCodec;
|
|
|
1977
|
+};
|
|
|
1978
|
+
|
|
1917
|
1979
|
/**
|
|
1918
|
1980
|
* Munges the stereo flag as well as the opusMaxAverageBitrate in the SDP, based
|
|
1919
|
1981
|
* on values set through config.js, if present.
|
|
|
@@ -2121,17 +2183,20 @@ TraceablePeerConnection.prototype.configureAudioSenderEncodings = function(local
|
|
2121
|
2183
|
* @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.
|
|
2122
|
2184
|
*/
|
|
2123
|
2185
|
TraceablePeerConnection.prototype.configureVideoSenderEncodings = function(localVideoTrack = null) {
|
|
|
2186
|
+ const preferredCodec = this.codecSettings.codecList[0];
|
|
|
2187
|
+
|
|
2124
|
2188
|
if (localVideoTrack) {
|
|
2125
|
2189
|
return this.setSenderVideoConstraints(
|
|
2126
|
2190
|
this._senderMaxHeights.get(localVideoTrack.getSourceName()),
|
|
2127
|
|
- localVideoTrack);
|
|
|
2191
|
+ localVideoTrack,
|
|
|
2192
|
+ preferredCodec);
|
|
2128
|
2193
|
}
|
|
2129
|
2194
|
const promises = [];
|
|
2130
|
2195
|
|
|
2131
|
2196
|
for (const track of this.getLocalVideoTracks()) {
|
|
2132
|
2197
|
const maxHeight = this._senderMaxHeights.get(track.getSourceName()) ?? VIDEO_QUALITY_LEVELS[0].height;
|
|
2133
|
2198
|
|
|
2134
|
|
- promises.push(this.setSenderVideoConstraints(maxHeight, track));
|
|
|
2199
|
+ promises.push(this.setSenderVideoConstraints(maxHeight, track, preferredCodec));
|
|
2135
|
2200
|
}
|
|
2136
|
2201
|
|
|
2137
|
2202
|
return Promise.allSettled(promises);
|
|
|
@@ -2230,9 +2295,10 @@ TraceablePeerConnection.prototype.setRemoteDescription = function(description) {
|
|
2230
|
2295
|
*
|
|
2231
|
2296
|
* @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.
|
|
2232
|
2297
|
* @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.
|
|
|
2298
|
+ * @param {preferredCodec} - The video codec that needs to be configured on the sender associated with the video source.
|
|
2233
|
2299
|
* @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.
|
|
2234
|
2300
|
*/
|
|
2235
|
|
-TraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight, localVideoTrack) {
|
|
|
2301
|
+TraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeight, localVideoTrack, preferredCodec) {
|
|
2236
|
2302
|
if (frameHeight < 0 || isNaN(frameHeight)) {
|
|
2237
|
2303
|
throw new Error(`Invalid frameHeight: ${frameHeight}`);
|
|
2238
|
2304
|
}
|
|
|
@@ -2248,8 +2314,10 @@ TraceablePeerConnection.prototype.setSenderVideoConstraints = function(frameHeig
|
|
2248
|
2314
|
return Promise.resolve();
|
|
2249
|
2315
|
}
|
|
2250
|
2316
|
|
|
|
2317
|
+ const codec = preferredCodec ?? this.codecSettings.codecList[0];
|
|
|
2318
|
+
|
|
2251
|
2319
|
return this._updateVideoSenderParameters(
|
|
2252
|
|
- () => this._updateVideoSenderEncodings(frameHeight, localVideoTrack));
|
|
|
2320
|
+ () => this._updateVideoSenderEncodings(frameHeight, localVideoTrack, codec));
|
|
2253
|
2321
|
};
|
|
2254
|
2322
|
|
|
2255
|
2323
|
/**
|
|
|
@@ -2274,10 +2342,12 @@ TraceablePeerConnection.prototype._updateVideoSenderParameters = function(nextFu
|
|
2274
|
2342
|
*
|
|
2275
|
2343
|
* @param {number} frameHeight - The max frame height to be imposed on the outgoing video stream.
|
|
2276
|
2344
|
* @param {JitsiLocalTrack} - The local track for which the sender constraints have to be applied.
|
|
|
2345
|
+ * @param {preferredCodec} - The video codec that needs to be configured on the sender associated with the video source.
|
|
2277
|
2346
|
* @returns {Promise} promise that will be resolved when the operation is successful and rejected otherwise.
|
|
2278
|
2347
|
*/
|
|
2279
|
|
-TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHeight, localVideoTrack) {
|
|
|
2348
|
+TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHeight, localVideoTrack, preferredCodec) {
|
|
2280
|
2349
|
const videoSender = this.findSenderForTrack(localVideoTrack.getTrack());
|
|
|
2350
|
+ const isScreensharingTrack = localVideoTrack.getVideoType() === VideoType.DESKTOP;
|
|
2281
|
2351
|
|
|
2282
|
2352
|
if (!videoSender) {
|
|
2283
|
2353
|
return Promise.resolve();
|
|
|
@@ -2288,7 +2358,7 @@ TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHe
|
|
2288
|
2358
|
return Promise.resolve();
|
|
2289
|
2359
|
}
|
|
2290
|
2360
|
|
|
2291
|
|
- const isSharingLowFpsScreen = localVideoTrack.getVideoType() === VideoType.DESKTOP && this._capScreenshareBitrate;
|
|
|
2361
|
+ const isSharingLowFpsScreen = isScreensharingTrack && this._capScreenshareBitrate;
|
|
2292
|
2362
|
|
|
2293
|
2363
|
// Set the degradation preference.
|
|
2294
|
2364
|
const preference = isSharingLowFpsScreen
|
|
|
@@ -2298,7 +2368,8 @@ TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHe
|
|
2298
|
2368
|
parameters.degradationPreference = preference;
|
|
2299
|
2369
|
|
|
2300
|
2370
|
// Calculate the encodings active state based on the resolution requested by the bridge.
|
|
2301
|
|
- const codec = this.getConfiguredVideoCodec();
|
|
|
2371
|
+ const codecForCamera = preferredCodec ?? this.getConfiguredVideoCodec(localVideoTrack);
|
|
|
2372
|
+ const codec = isScreensharingTrack ? this._getPreferredCodecForScreenshare(codecForCamera) : codecForCamera;
|
|
2302
|
2373
|
const activeState = this.tpcUtils.calculateEncodingsActiveState(localVideoTrack, codec, frameHeight);
|
|
2303
|
2374
|
let bitrates = this.tpcUtils.calculateEncodingsBitrates(localVideoTrack, codec, frameHeight);
|
|
2304
|
2375
|
const scalabilityModes = this.tpcUtils.calculateEncodingsScalabilityMode(localVideoTrack, codec, frameHeight);
|
|
|
@@ -2321,6 +2392,7 @@ TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHe
|
|
2321
|
2392
|
if (parameters.encodings.hasOwnProperty(idx)) {
|
|
2322
|
2393
|
const {
|
|
2323
|
2394
|
active = undefined,
|
|
|
2395
|
+ codec: currentCodec = undefined,
|
|
2324
|
2396
|
maxBitrate = undefined,
|
|
2325
|
2397
|
scalabilityMode = undefined,
|
|
2326
|
2398
|
scaleResolutionDownBy = undefined
|
|
|
@@ -2353,6 +2425,16 @@ TraceablePeerConnection.prototype._updateVideoSenderEncodings = function(frameHe
|
|
2353
|
2425
|
} else {
|
|
2354
|
2426
|
parameters.encodings[idx].scalabilityMode = undefined;
|
|
2355
|
2427
|
}
|
|
|
2428
|
+
|
|
|
2429
|
+ const expectedPattern = `${MediaType.VIDEO}/${codec.toUpperCase()}`;
|
|
|
2430
|
+
|
|
|
2431
|
+ // Configure the codec here if its supported.
|
|
|
2432
|
+ if (this.usesCodecSelectionAPI() && currentCodec?.mimeType !== expectedPattern) {
|
|
|
2433
|
+ const matchingCodec = parameters.codecs.find(pt => pt.mimeType === expectedPattern);
|
|
|
2434
|
+
|
|
|
2435
|
+ parameters.encodings[idx].codec = matchingCodec;
|
|
|
2436
|
+ needsUpdate = true;
|
|
|
2437
|
+ }
|
|
2356
|
2438
|
}
|
|
2357
|
2439
|
}
|
|
2358
|
2440
|
|