Render of Peer Video fails after repeat video call session

Hi,

(We are using Ionic VueJS)

We are struggling how to make the renderVideo stable.

On first session (video call), it will work perfectly. But after repeated calls, we encounter this error and then one side of the call; Peer video render will be blank and black.

Any help or suggestion is appreciated

Regards,

Neil Oswald

=== RENDER VIDEO  ===
c56504b9-3903-45cd-8e4e-0b6305eb1e86:1 Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at f.JsMediaSDK_VideoRender_interval (c56504b9-3903-45cd-8e4e-0b6305eb1e86:1:181982)
f.JsMediaSDK_VideoRender_interval @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
setInterval (async)
f.Start_Draw @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
(anonymous) @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
c56504b9-3903-45cd-8e4e-0b6305eb1e86:1 Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at f.JsMediaSDK_VideoRender_interval (c56504b9-3903-45cd-8e4e-0b6305eb1e86:1:181982)
f.JsMediaSDK_VideoRender_interval @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
setInterval (async)
f.Start_Draw @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
(anonymous) @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
c56504b9-3903-45cd-8e4e-0b6305eb1e86:1 Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at f.JsMediaSDK_VideoRender_interval (c56504b9-3903-45cd-8e4e-0b6305eb1e86:1:181982)
f.JsMediaSDK_VideoRender_interval @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
setInterval (async)
f.Start_Draw @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
(anonymous) @ c56504b9-3903-45cd-8e4e-0b6305eb1e86:1
c56504b9-3903-45cd-8e4e-0b6305eb1e86:1 Uncaught TypeError: Cannot read properties of undefined (reading 'width')

This is our render code:

zoomClient.on(“peer-video-state-change”, async (payload) => {
        const { action, userId } = payload;
        console.log(
          “=== PEER VIDEO STATE CHANGE (action,peer,self)===“,
          action,
          userId,
          zoomClient.getCurrentUserInfo().userId,
          JSON.stringify(payload)
        );
        // default
        const width = 640;
        const height = 360;
        if (userId != zoomClient.getCurrentUserInfo().userId) {
          if (action === “Start”) {
            // this.toggleVideo(true, this.videoCanvas, userId, 1080, 540);
            console.log(“=== START RENDER VIDEO ===“, userId);
            // set video on from other party to ON
            this.isPeerVideoOn = true;
            try {
              console.log(“=== STARTING VIDEO  ===“);
              if (!zoomStream.isCapturingVideo()) {
                // await zoomStream.startVideo({ videoElement: this.partyVideo });
                await zoomStream.startVideo({ videoElement: this.selfVideo });
              }
            } catch (e) {
              await zoomStream.startVideo();
              console.log(“=== START VIDEO ERROR ===“, e);
            }
            try {
              console.log(“=== RENDER VIDEO  ===“);
              zoomStream.renderVideo(
                this.videoCanvas,
                userId,
                360,
                180,
                0,
                0,
                VideoQuality.Video_360P
              );
            } catch (e) {
              console.log(“=== RENDER VIDEO ERROR ===“, e);
            }
          } else if (action === “Stop”) {
            // this.toggleVideo(false, this.videoCanvas, userId, 1080, 540);
            console.log(
              “=== STOP RENDER VIDEO ===“,
              userId
            );
            // set video on from other party to ON
            this.isPeerVideoOn = false;
            try {
              zoomStream.stopRenderVideo(this.videoCanvas, userId);
              // await zoomStream.clearVideoCanvas(this.videoCanvas, “blue”);
              // await zoomStream.stopVideo()
            } catch (e) {
              console.log(
                “=== STOP RENDER VIDEO ERRROR === “,
                JSON.stringify(e)
              );
            }
          }
        }
      });

Hey @neiloswald

Thanks for your feedback.

In the post you mentioned

On first session (video call), it will work perfectly. But after repeated calls, we encounter this error and then one side of the call; Peer video render will be blank and black.

Did you reuse the HTMLCanvasElement? In the Video SDK, the canvas will be transferred to the OffscreenCanvas, which can be used in the worker thread but can no longer be used in the main thread. Could you please check whether a new canvas is created when restarting a session?

Thanks
Vic

Thanks @vic.yang for a quick reply.

We are (re) using same HTMLCanvasElement.

I am not aware how to utilize the OffscreenCanvas. Is this in your documentation or sample apps?

Let us know (do you have guide) what is the best practice or pattern, of the Video Call. Do we need to initialize the Zoom Client every session?

Our application is basic, two party call. We have one main canvas to display the peer (remote) video. And another canvas (smaller inset) to render the Self video.

Thanks,

Neil Oswald

Hey @neiloswald

OffscreenCanvas is used inside the Video SDK. Here I just explained why the canvas element cannot be reused.

We suggest creating a new canvas element for the new session. It can be done by

const newCanvas = canvas.cloneNode(true) ;
canvas.parentNode.replaceChild(newCanvas, canvas);

Or if you are using a framework, rerender the canvas, and make sure it is a new instance.

Thanks
Vic

1 Like

Thank you @vic.yang we will explore this idea.

I will give feedback later.

Hi @vic.yang

Good day.

Upon our initial test using newCanvas, it seems to be working and stable. We will do further testing and give you feedback.

Some observations though:

  1. We were using two separate canvases to render the Peer and the Self View. For both we use your trick of using new canvas by cloning. But we encountered error something like “OffscreenCanvas index error”. The question , is this a good idea to use separate Canvases for the Self and Peer View considering the OffscreenCanvas matters.

  2. We tried alternative of using one canvas to render both the Peer and Self Video AND by the way the Self Video overlaps (inset in lower left corner) with the Peer Video. This works however the Self Video is flickering all the time. The question is it possible to Overlap two videos in one Canvas. If not do you have any suggestion how to fix the flickering.

  3. This seems to be redundant, but would like to get your opinion if using NodeJS / Ionic VueJS will not cause any major issues with Zoom Video SDK.

Thank you and I appreciate your support.

Neil Oswald

Hey @neiloswald

  1. We recommend using a single canvas to serve the videos. But it requires Cross-Origin Isolation on the Chromium browsers. Or enable enforceMultipleVideos in the init method.
  2. The coordinates of the video can be specified, you can avoid the overlapping of two videos on the same canvas by calculation.
  3. The Video SDK Web is a stack-less library. Choose your preferred UI framework to achieve your application.

Thanks
Vic

Thank you @vic.yang , we appreciate your support.

@neiloswald,

Glad @vic.yang insight was helpful. Thank you for posting in the Developer Forum.

1 Like

Thank you so much for helping us a lot. I was looking for the solution and got it from here. Keep sharing amazing helpful content.