From dde6f8352482d5f394109f51a6536c2920e14911 Mon Sep 17 00:00:00 2001 From: Jacob Schlecht Date: Sun, 23 Aug 2026 16:04:22 -0600 Subject: [PATCH 1/3] feat: Allow applying new constraints to a screen share Signed-off-by: Jacob Schlecht --- src/room/track/LocalVideoTrack.ts | 40 +++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/room/track/LocalVideoTrack.ts b/src/room/track/LocalVideoTrack.ts index 5c99fc9b0c..9b43650a60 100644 --- a/src/room/track/LocalVideoTrack.ts +++ b/src/room/track/LocalVideoTrack.ts @@ -19,10 +19,16 @@ import type { LoggerOptions } from '../types'; import { isFireFox, isMobile, isSVCCodec, isWeb } from '../utils'; import LocalTrack from './LocalTrack'; import { Track, VideoQuality } from './Track'; -import type { TrackPublishOptions, VideoCaptureOptions, VideoCodec } from './options'; +import type { + ScreenShareCaptureOptions, + TrackPublishOptions, + VideoCaptureOptions, + VideoCodec, + VideoEncoding, +} from './options'; import { isBackupVideoCodec } from './options'; import type { TrackProcessor } from './processor/types'; -import { constraintsForOptions } from './utils'; +import { constraintsForOptions, screenCaptureToDisplayMediaStreamOptions } from './utils'; export class SimulcastTrackInfo { codec: VideoCodec; @@ -285,6 +291,36 @@ export default class LocalVideoTrack extends LocalTrack { await this.onSenderTrackSwapped(); } + async applyScreenShareConstraints( + constraints: Pick, + videoEncoding?: VideoEncoding, + ): Promise { + // Only valid for screen shares + if (this.source !== Track.Source.ScreenShare) { + return; + } + + const mediaTrackConstraints = screenCaptureToDisplayMediaStreamOptions(constraints); + if (typeof mediaTrackConstraints.video === 'boolean') { + return; + } + + const unlock = await this.trackChangeLock.lock(); + try { + await this.mediaStreamTrack.applyConstraints(mediaTrackConstraints.video); + if (videoEncoding && this.publishOptions) { + this.publishOptions.screenShareEncoding = videoEncoding; + } + if (constraints.contentHint) this.mediaStreamTrack.contentHint = constraints.contentHint; + } finally { + unlock(); + } + + // Since resolution or encoding might be different, recompute the sender's encoding + // parameters. + await this.onSenderTrackSwapped(); + } + protected override async onSenderTrackSwapped(): Promise { await this.refreshSenderEncodings(); } From e4f52b75ae89c6ecb1329798c320d242936bb8fa Mon Sep 17 00:00:00 2001 From: Jacob Schlecht Date: Sun, 23 Aug 2026 16:20:10 -0600 Subject: [PATCH 2/3] fix: Don't silently drop contentHint and do encoding set outside lock Signed-off-by: Jacob Schlecht --- src/room/track/LocalVideoTrack.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/room/track/LocalVideoTrack.ts b/src/room/track/LocalVideoTrack.ts index 9b43650a60..fb002de23e 100644 --- a/src/room/track/LocalVideoTrack.ts +++ b/src/room/track/LocalVideoTrack.ts @@ -301,15 +301,15 @@ export default class LocalVideoTrack extends LocalTrack { } const mediaTrackConstraints = screenCaptureToDisplayMediaStreamOptions(constraints); - if (typeof mediaTrackConstraints.video === 'boolean') { - return; + + if (videoEncoding && this.publishOptions) { + this.publishOptions.screenShareEncoding = videoEncoding; } const unlock = await this.trackChangeLock.lock(); try { - await this.mediaStreamTrack.applyConstraints(mediaTrackConstraints.video); - if (videoEncoding && this.publishOptions) { - this.publishOptions.screenShareEncoding = videoEncoding; + if (typeof mediaTrackConstraints.video === 'object') { + await this.mediaStreamTrack.applyConstraints(mediaTrackConstraints.video); } if (constraints.contentHint) this.mediaStreamTrack.contentHint = constraints.contentHint; } finally { From ccbcbe9034a2502c7782a08c01081f80d9ef47e8 Mon Sep 17 00:00:00 2001 From: Jacob Schlecht Date: Sun, 23 Aug 2026 16:31:03 -0600 Subject: [PATCH 3/3] fix: Apply new encoding to a screenshare even if dimensions don't change Signed-off-by: Jacob Schlecht --- src/room/track/LocalVideoTrack.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/room/track/LocalVideoTrack.ts b/src/room/track/LocalVideoTrack.ts index fb002de23e..b1404ecc9c 100644 --- a/src/room/track/LocalVideoTrack.ts +++ b/src/room/track/LocalVideoTrack.ts @@ -318,11 +318,11 @@ export default class LocalVideoTrack extends LocalTrack { // Since resolution or encoding might be different, recompute the sender's encoding // parameters. - await this.onSenderTrackSwapped(); + await this.onSenderTrackSwapped(true); } - protected override async onSenderTrackSwapped(): Promise { - await this.refreshSenderEncodings(); + protected override async onSenderTrackSwapped(ignoreDims = false): Promise { + await this.refreshSenderEncodings(ignoreDims); } /** @@ -331,7 +331,7 @@ export default class LocalVideoTrack extends LocalTrack { * if the track hasn't been published yet or if the track is in performance-optimized * mode (which manages its own encodings). */ - private async refreshSenderEncodings() { + private async refreshSenderEncodings(ignoreDims = false) { if (!this.sender || !this.publishOptions || this.optimizeForPerformance) { return; } @@ -349,6 +349,7 @@ export default class LocalVideoTrack extends LocalTrack { } if ( + !ignoreDims && this.lastEncodedDimensions && this.lastEncodedDimensions.width === dims.width && this.lastEncodedDimensions.height === dims.height