Description
When a call is ended from the connection-change event returning a Closed state the camera/microphone are still shown as in use on the browser after .
Troubleshooting Routes
I’ve made sure to run stopVideo and stopAudio when the call ends and I’ve tried fetching all the active mediaStreams from the navigator and stopping all tracks. There has been no effect.
How To Reproduce
Join the session as a host
Join the session from another device as a guest
End the entire session as the host
See the call end for the second user
See the media devices still marked as active in the browser of the second user
Of note: I’m running 1.12.12 unlike the original poster.
Both the microphone and camera stay active for the participant when the meeting ends via the host ending with ‘client.leave(true) ‘.
Attempting to catch the session ending in the event listener ‘connection-change’ and calling stopVideo() or stopAudio() fails with the error ‘IMPROPER_MEETING_STATE’.
The browser does not release the camera/microphone until a browser refresh is done.
Edit
Some additional information for you @vic.yang.
I only notice this issue on safari
I have tried multiple solutions, none worked. The only way I’ve been able to drop the camera/microphone if the host ends the session is via a refresh.
Tried: Looping through all the devices manually and manually disabling all of them using mediaquery after the session has ended
Tried: Calling .stopVideo() on the participant side on component unmount (prior to the connection-change event firing)
Tried: calling Client.destroyClient() on component unmount.
Having the same issue using either Web Zoom client, or Mac desktop client.
Camera icon on macOS menu bar remains active (lit green) when Zoom sessions are terminated (when clicked, shows Zoom as the app holding the Webcam hostage…). I’m on a Mac mini M4 running the latest version of Sequoia.
Thanks for outlining the issue clearly. This behavior usually occurs when media tracks (camera/microphone) are not explicitly stopped at all necessary exit points in a Zoom Video SDK session.
Even if stopVideo() and stopAudio() are called, the browser may still show the devices as active unless all underlying media tracks are properly stopped and released.
To fully clean up media devices, I recommend handling it in three key places:
1. On client.leave()
await zoomClient.leave();
cleanupMediaTracks();
2. On connection-change to Closed
zoomClient.on('connection-change', ({ state }) => {
if (state === 'Closed') {
cleanupMediaTracks();
}
});
function cleanupMediaTracks() {
// Zoom Video SDK media
mediaStream?.stopAudio?.();
mediaStream?.stopVideo?.();
// Raw browser MediaStream (if used)
if (localMediaStream) {
localMediaStream.getTracks().forEach(track => track.stop());
}
}
mediaStream refers to the Zoom SDK’s media stream (client.getMediaStream()), while localMediaStream is any stream from getUserMedia() you may be managing manually.
With this setup, media devices should release properly after the session ends or the tab is closed.
Let me know if you need help structuring this into a reusable media handler.