Skip to content

Stale <video> element left inside VideoStreamRendererView target after internal stream re-subscription — remote participant renders twice #6075

Description

Describe the bug

In a Teams interop meeting, the calling SDK intermittently leaves a previous <video> element inside a remote participant's view target while appending a fresh one. The render target div (the element handed to StreamMedia via videoStream.renderElement) then contains two sibling <video> elements:

<div data-ui-id="stream-media-container" class="css-199">
  <div style="width: 100%; height: 100%;">   <!-- VideoStreamRendererView target -->
    <video playsinline disablepictureinpicture autoplay style="width: 100%; height: 100%; object-fit: cover;"></video>
    <video playsinline disablepictureinpicture autoplay style="width: 100%; height: 100%; object-fit: cover;"></video>
  </div>
</div>

Both videos are live. Since each is height: 100%, they stack and overflow the tile, so the participant appears twice on screen (the second copy paints below the video gallery, looking like a phantom extra tile). DevTools screenshot of the doubled target available on request.

Only one view is ever created per stream on our side. We use the stateful client with usePropsFor(VideoGallery) handlers; onCreateRemoteStreamView is only called when videoStream.renderElement is unset, and the stateful client's own renderInfo status guards (Rendered / Rendering / Stopping) collapse concurrent calls. Two stateful renderers would also produce two targets — here it is one target with two videos, i.e. two internal renderer generations sharing one container.

To Reproduce

  1. Join a Teams meeting as an anonymous ACS user (meeting-link join), React web app rendering remote video tiles via the stateful client + StreamMedia.
  2. Have participants with cameras on join one by one (we reproduce reliably around the 5th camera-on participant joining, while the gallery is reflowing).
  3. Inspect a tile's stream-media-container: the target div holds two <video> elements.

Our instrumentation (counts of tile containers vs <video> elements in the gallery, sampled 2.5 s after each membership change) shows the moment it happens and that the stale element persists indefinitely across later membership changes, including other participants leaving and rejoining:

19:15:44  tiles=4  videos=4    (clean)
19:15:54  tiles=5  videos=6    (5th participant joined — leak)
19:23:04  tiles=4  videos=5
19:23:10  tiles=3  videos=4
19:24:19  tiles=2  videos=3    (still carrying the stale element 9 min later)

We have also hit this in production twice (2026-07-14, 2026-08-27) in Teams interop meetings with 10+ participants and camera on/off churn.

Expected behavior

A view target contains exactly one <video> element; on internal re-subscription (simulcast/quality layer switch, stream drop/recover) the previous element is removed or reused.

Versions

  • @azure/communication-calling: reproduced on 1.42.1 and 1.46.1
  • @azure/communication-react: 1.31.0 and 1.34.0
  • @azure/communication-calling-effects: 1.3.2
  • React 18.3.1
  • Electron 37.10.3 (Chromium ~140) on Windows 10/11; same behavior with and without DirectComposition video overlays disabled
  • Meeting type: Teams interop, anonymous join via meeting link

Ask

Is this a known issue in the calling SDK's VideoStreamRenderer, and is a fix planned? Happy to provide the full DOM captures, our diagnostic logs, and timing details.

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