Repository navigation
Conversation
The SFU stopped echoing the RFC 8853 pause markers, so a publisher answer re-enables every simulcast layer. Dynacast only signals a change, so the pause was never re-sent and the layers it had paused kept uploading until the subscribed quality changed again. The engine now emits a refresh once the answer is applied, and the room re-applies each local video track's last subscribed codecs to its sender. Re-applying a pause forces the write, because the answer re-enabled the layers without going through setParameters and a conditional write would see no difference against a cached view of the sender. Only codecs that actually have a paused layer are forced, so a renegotiation costs no native call in the steady state and a backup codec's stored encodings are not stamped over its sender. Dynacast updates keep their behaviour. Also moves the shared media fakes into test/mock/. Ports client-sdk-js#2121.
There was a problem hiding this comment.
Devin Review found 2 potential issues.
1 flag not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)
| if (subscribedCodecs.isEmpty) { | ||
| return; | ||
| } |
There was a problem hiding this comment.
🔴 Legacy dynacast pauses stay re-enabled
After a legacy subscribedQualities update, refreshSubscribedCodecs has no codecs to replay. The legacy update handler never records them, so a publisher answer leaves paused layers uploading.
Learn more
The room supports two shapes of dynacast update: a list of subscribed codecs and the older list of subscribed qualities. The latter goes straight to setPublishingLayers in the legacy update handler, without storing replayable state. After an answer re-enables paused layers, refreshSubscribedCodecs returns because its codec list is empty. Those layers keep uploading until the SFU changes the subscription again.
Example: A server sends only subscribedQualities asking a camera to disable LOW. An audio-track publication triggers a publisher renegotiation; the resulting answer re-enables LOW, and the refresh cannot restore the pause.
Recommended fix: Save the last legacy quality update per local video track and replay it through setPublishingLayers with a forced write after publisher answers. Clear this state when the corresponding publish session ends.
Was this helpful? React with 👍 or 👎 to provide feedback.
| Future<void> refreshSubscribedCodecs() async { | ||
| if (subscribedCodecs.isEmpty) { | ||
| return; | ||
| } | ||
| try { | ||
| await setPublishingCodecs(subscribedCodecs, this, force: true); |
There was a problem hiding this comment.
🔴 Old pauses affect republished video
When a video track is republished, refreshSubscribedCodecs replays subscriptions from its previous publication. Unpublish clears senders but not subscribedCodecs, so the new video can remain paused until another update.
Learn more
A LocalVideoTrack object can be reused across publications, and a full reconnect also republishes the same object. Unpublish and rePublishAllTracks clear its sender-related simulcast state, but not its last subscribed codecs. The refresh now treats that old list as instructions for the new sender after its answer arrives. If the previous publication had all layers disabled, the new publication can start with all layers disabled too, until a new subscription update is processed.
Example: A camera's last subscription disables LOW and MEDIUM; the app unpublishes and republishes the same camera track. Its next publisher answer triggers a forced write of the previous publication's LOW/MEDIUM pause to the new sender.
Recommended fix: Reset subscription state when a track starts a new publish session, including unpublish and full reconnect, rather than carrying the old session's codec list into the new sender. Ensure a current-session SFU update can be applied before or after the answer without being overwritten.
Was this helpful? React with 👍 or 👎 to provide feedback.
The SFU stopped echoing the RFC 8853 pause markers, so a publisher answer
re-enables every simulcast layer. Dynacast only signals a change, so the
pause was never re-sent and the layers it had paused kept uploading until
the subscribed quality changed again. The engine now emits a refresh once
the answer is applied, and the room re-applies each local video track's
last subscribed codecs to its sender.
Re-applying a pause forces the write, because the answer re-enabled the
layers without going through setParameters and a conditional write would
see no difference against a cached view of the sender. Only codecs that
actually have a paused layer are forced, so a renegotiation costs no
native call in the steady state and a backup codec's stored encodings are
not stamped over its sender. Dynacast updates keep their behaviour.
Also moves the shared media fakes into test/mock/.
Ports livekit/client-sdk-js#2121.