Skip to content

setCameraEnabled ignores captureOptions when the publication is muted #2101

Description

@kaelvar

Describe the bug

What I'm expecting

setCameraEnabled(true, captureOptions) applies captureOptions to the camera it brings back.

What happens instead

captureOptions is silently ignored whenever a muted publication for that source already exists — which is the normal state after setCameraEnabled(false), since disabling a camera mutes the publication rather than unpublishing it (only screen share unpublishes).

LocalParticipant.setTrackEnabled:

let track = this.getTrackPublication(source);
if (enabled) {
  if (track) {
    await track.unmute();                                  // options never used
  } else {
    localTracks = await this.createTracks({ video: options ?? true });
  }

For a camera source, LocalVideoTrack.unmute() calls restart(undefined, true), and LocalTrack.restart() falls back to this._constraints when called without constraints — so the track comes back with the resolution, frame rate and facing mode it was originally created with, not the ones just requested.

The parameter is accepted and dropped without a warning, which is the part that costs downstream debugging time: the call looks correct and the UI shows the new setting, while the publisher keeps sending the old one.

Reproduction

await room.localParticipant.setCameraEnabled(true, {
  resolution: VideoPresets.h720.resolution,
});
await room.localParticipant.setCameraEnabled(false);
await room.localParticipant.setCameraEnabled(true, {
  resolution: VideoPresets.h1080.resolution,
});
// getSettings() on the published track still reports 1280x720

Found while working on suitenumerique/meet, where the UI passes the user's chosen resolution to the camera toggle: a resolution picked while the camera is off is never applied when it is turned back on.

Logs

No warning is emitted on the dropped options; `restart` logs only
"restarting track with constraints" with the previous constraints.

System Info

livekit-client: 2.21.0
macOS 26.5, Chrome 152.0.7977.84

The branch above is identical in the published ESM builds of 2.19.0, 2.21.0 and 2.22.3, so this is not specific to one version or browser.

Severity

serious, but I can work around it

Suggested fix

On the unmute branch, apply options when they differ from the track's current constraints — or, at minimum, log that they were dropped.

The workarounds available to an application are both unattractive: a second getUserMedia right after unmute, which visibly blinks the camera, or unpublishing the track on camera-off instead of muting it, which forces a renegotiation on every toggle.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions