Error when switching from virtual camera back to real camera — "CAN_NOT_FIND_CAMERA"

Description

I’m trying to implement a virtual camera by overriding MediaDevices.prototype.enumerateDevices and MediaDevices.prototype.getUserMedia. I’m able to successfully switch to the virtual camera within Zoom. However, when I attempt to switch back to the physical (built-in) camera, I receive the following error. I have confirmed that the device ID I’m trying to switch to is valid — it was obtained from a call to enumerateDevices() .

Browser Console Error

Error: {"type":"CAN_NOT_FIND_CAMERA","reason":"cannot find target camera"}

Which Web Video SDK version?
2.1.0

Video SDK Code Snippets
Here are the override implementations I’m using for enumerateDevices and getUserMedia to simulate a virtual camera:

const enumerateDevicesFn = navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices);
const getUserMediaFn = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);

MediaDevices.prototype.enumerateDevices = async function () {
    const res = await enumerateDevicesFn.call(navigator.mediaDevices);
    let dv = VIRTUAL_DEVICE;
    dv = { ...dv, toJSON: () => dv }; // Ensure toJSON method is available
    res.push(dv);
    return res
}

MediaDevices.prototype.getUserMedia = async function (...args) {
    if (args.length && args[0].video && args[0].video.deviceId) {
        if (
            args[0].video.deviceId === VIRTUAL_DEVICE.deviceId ||
            args[0].video.deviceId.exact === VIRTUAL_DEVICE.deviceId
        ) {
            const constraints = {
                video: { ...(args?.video ?? {}) },
                audio: false
            }
            const res = await getUserMediaFn.call(
                navigator.mediaDevices,
                constraints
            )

            const canvas = document.getElementById(AVATAR_CANVAS_ID)
            if (res && canvas) {
                return canvas.captureStream(30)
            }
        }
    }

    const res = await getUserMediaFn.call(navigator.mediaDevices, ...args);
    return res;
}

To Reproduce

  1. Join a Zoom Video SDK session.
  2. Start the session using a real physical camera (works as expected).
  3. Switch to the virtual camera (also works).
  4. Attempt to switch back to the physical camera.
  5. Observe the error:
Error: {"type":"CAN_NOT_FIND_CAMERA","reason":"cannot find target camera"}

Screenshots
If applicable, add screenshots to help explain your problem.

Device :

  • Device: MacBook Pro (Apple Silicon)
  • OS: macOS (Sonoma)
  • Browser: Chrome
  • Browser Version: 137.0.6482.114 (Official Build) (arm64)

Session ID :
4OoNSCdnRRSq3GeJfQzaxA==

Hi @vic.yang,
Could you please help take a look at this issue when you have a moment? I’d really appreciate your insights.

Hi @namlv

Thanks for your feedback.

We haven’t actually encountered cases where enumerateDevices and getUserMedia were overridden, but when the error ‘cannot find target camera’ is returned, it’s usually because the provided deviceId doesn’t match any available devices.

We will evaluate this scenario and improve the method in the next version.

Thanks
Vic

@vic.yang Thank you for your response

I have already validated that the deviceId is correct before switching. In fact, I initially started the session using that same deviceId before switching to the virtual camera.

Let me briefly describe how I implemented this:
I first call getUserMedia with the real device’s deviceId and render its stream to a <canvas> element. Then, my virtual camera pulls video from that canvas as its source.

Before switching back to the real camera, I make sure to stop the stream from the virtual source and remove the canvas element from the DOM.

However, when I attempt to switch back using client.switchCamera(deviceId), I get the following error:

{ "type": "CAN_NOT_FIND_CAMERA", "reason": "cannot find target camera" }

Interestingly, if I stop the current camera and start a new stream using client.startVideo(deviceId) instead of switching, it works correctly.

Do you have any suggestions on how to make switchCamera() work in this setup, or any best practices to avoid this issue?

Hi @namlv

Interestingly, if I stop the current camera and start a new stream using client.startVideo(deviceId) instead of switching, it works correctly.

Yes.

We have encountered an edge case where overriding enumerateDevices and getUserMedia causes switchCamera to fail.

Currently, using stopVideo followed by startVideo({ cameraId }) serves as a workable workaround.

Thanks
Vic

Thanks again for your time and support!