Skip to content

Turn off the camera when the video is disabled during a call#18788

Open
vladopol wants to merge 2 commits into
nextcloud:mainfrom
vladopol:feat/release-camera-on-video-off-main
Open

Turn off the camera when the video is disabled during a call#18788
vladopol wants to merge 2 commits into
nextcloud:mainfrom
vladopol:feat/release-camera-on-video-off-main

Conversation

@vladopol

Copy link
Copy Markdown

Fixes #4008

Summary

During a call the camera hardware light stayed on even when the video was
disabled (and it kept the camera busy for other applications). This has been
reported for years, both in the browser and, more visibly, in the Talk Desktop
(Electron) client.

Digging into it, the camera was actually held by two independent grabs at
the same time, which is why previous attempts that only addressed one of them
never turned the light off:

  1. The call media pipeline kept the camera track alive and only disabled
    it (track.enabled = false) when the video was turned off. Chromium does not
    honour the "SHOULD release the device when all tracks are disabled" part of
    the mediacapture spec
    (see the corresponding Chromium issue), so the camera β€” and its light β€” stays
    on. Firefox releases it, Chromium/Electron does not.

  2. The in-call device buttons (LocalVideoControlButton /
    LocalAudioControlButton) subscribed to the shared device manager to build
    the device dropdown, which also grabbed a live camera stream that was never
    actually used for anything. This kept a second camera track alive for the
    whole call, independently of whether the video was enabled.

Selecting "None" as the camera turned the light off precisely because it
released both grabs (the pipeline via the videoInputId change and the
device buttons via their watcher). This PR fixes both so the light turns off
whenever the video is disabled.

Changes

The PR is split into two independent commits:

1. fix(call): release the camera used by in-call device buttons

The in-call control buttons only need the device list, not a live preview, so
they now subscribe to useDevices with { videoPreview: false }. A live video
stream is only grabbed when a subscriber actually shows a preview (the device
settings dialog). This removes the redundant camera grab (#2 above) β€” it also
means one fewer getUserMedia per call.

2. fix(call): release the camera when the video is disabled

  • MediaDevicesSource gets a videoActive state, orthogonal to the existing
    videoAllowed (permissions) state. When the video is disabled the video track
    is fully stopped (releasing the camera and turning off its light) instead
    of just disabled; when the video is enabled again the camera is grabbed anew.
  • LocalMedia.pauseVideo() / resumeVideo() drive that state.
  • LocalMediaModel now derives videoAvailable from whether a camera input
    device is selected
    rather than from the presence of a live track, so the
    video controls stay usable while the camera is released β€” including when the
    call is joined with the video already disabled. The model state while the
    video is off is otherwise identical to the previous "muted" state
    (videoAvailable: true, videoEnabled: false), so what is broadcast to other
    participants does not change.

Testing

Manual (Talk Desktop / Electron on macOS, HPB backend, with blur enabled):

  • Join with video on β†’ disable video β†’ camera light turns off; enable again
    β†’ camera comes back immediately.
  • Join with video off β†’ the camera light stays off; pressing the button
    enables the camera (the light turns on) instead of opening the device dialog,
    and disabling it again turns the light back off.
  • "None" device, camera switching from the dropdown, and background blur all
    keep working.

Automated:

  • New unit tests for MediaDevicesSource.setVideoActive() (release on disable,
    re-grab on enable, gating of start() and of device changes while inactive,
    no grab when not allowed).
  • Full existing suite stays green.

Notes

  • Nothing is removed from the UI: the control buttons, the device dropdown and
    the microphone level indicator are all unchanged. Only the redundant, unused
    video getUserMedia the buttons performed in the background is dropped.
    The audio capture used for the microphone level indicator is left untouched.
  • The camera is re-acquired when the video is enabled again (a fresh
    getUserMedia); in testing this was immediate.

Checklist

  • Tests (unit tests added, existing suite green)
  • Manually tested
  • Documentation (n/a)

vladopol added 2 commits July 25, 2026 01:00
The local video and audio control buttons subscribe to the shared
device manager to populate the device list, but that also grabbed a
live camera stream which was never actually used. As a result the
camera (and its hardware light) stayed on for the whole call even when
the video was disabled.

Let the in-call buttons subscribe without a live video preview, so the
camera is only grabbed by components that actually show a preview (the
device settings dialog).

Partial fix for nextcloud#4008

Signed-off-by: Vladimir Poluliashenko <vladopol@gmail.com>
When the video was disabled during a call the video track was only
disabled (track.enabled = false) but kept alive, so Chromium did not
release the camera and its hardware light stayed on (Chromium does not
honour the "SHOULD release the device" part of the mediacapture spec).

Fully stop the camera track when the video is disabled (releasing the
camera and turning off its hardware light) and grab it again when the
video is enabled, via a new "videoActive" state in MediaDevicesSource
that is orthogonal to "videoAllowed" (permissions).

Keep "videoAvailable" based on whether a camera input device is
selected rather than on the presence of a live track, so the video
controls stay usable while the camera is released, including when the
call is joined with the video already disabled.

Partial fix for nextcloud#4008

Signed-off-by: Vladimir Poluliashenko <vladopol@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Webcam hardware light is on during audio call

1 participant