I’m migrating from Twilio to Zoom Video SDK and I’m having a problem rendering the videos for remote participants using the code provided in the documentation.
Here is what I’m doing:
zoomClient.on("peer-video-state-change", (payload) => {
const mediaStream = zoomClient.getMediaStream();
if (payload.action === "Start") {
mediaStream.attachVideo(payload.userId, 3).then((userVideo) => {
const videoPlayerContainer = document.querySelector("video-player-container") as Element;
videoPlayerContainer.appendChild(userVideo as VideoPlayer);
});
} else if (payload.action === "Stop") {
mediaStream.detachVideo(payload.userId);
}
});
And then in the HTML I have the <video-player-container></video-player-container>.
The participants are joining after the local participant and I don’t get any errors but the remote participant video just shows a black screen.
Any ideas on what I might be doing wrong?
Welcome!
Can you provide me some more information as to where and how this event listener is being implemented? Do you know if it is successfully subscribed and if your code block is actually running?
The element created by mediaStream.attachVideo may not have an initial size, which could be causing the black screen. Since it’s an HTML element, you can add a class to it and then set its width and height in CSS.
I can tell the event handler is working since I added some console logs inside to render the returned video player and I can see it being added when I inspect the page. I’m also rendering the local user video using a similar approach and have no problems with that one:
You can obtain it from the Dashboard on the Video SDK Web portal page, or if your session is still ongoing, you can retrieve it using client.getSessionInfo().
The only error I’m seeing in the console at the moment is Uncaught (in promise) DOMException: The play() request was interrupted by a new load request.
I’ve created a small test app where the problem is happening so it will be easier to share with you. I’m using Next.js
Thank you for sharing the complete code example with us.
I’ve tested the code you provided and found some areas that need improvement. Below, I will list out some points for modification and explain the reasons.
Since the video player does not have a default width and height, you need to set them manually. You previously set the width; the default height should be 9/16 of the width. Therefore, I added the aspect-ratio property to specify the height.
We recommend enabling SharedArrayBuffer to improve performance. You can refer to this doc.
Since the test example doesn’t have these configurations, we recommend specifying the enforceMultipleVideos option as true when calling the client.init method.
This allows placing multiple video-player elements within the video-player-container even when SharedArrayBuffer is disabled. Otherwise, you would need one video-player-container per video.
Correspondingly,Video SDK Web provide the stream.isSupportMultipleVideos() method to detect whether this feature is supported.
Please feel free to reach out if you have any further questions or require additional assistance.
The changes you recommended worked, but now I’m trying to attach the video to an existing video player, so I can add some styling to each participant’s video, and I’m having some issues.
I created a new component (ParticipantContainer.tsx) to render the participant video player and I’m running mediaStream.attachVideo(participant.userId, 3, videoPlayerRef.current) when the participant.bVideoOn changes to true.
This works for the local participant but not for the remote participant. I’ve also noticed that, even for the local participant, if I toggle the video on and off a few times, the video stops rendering and the node-id of the video player is changed to 0 instead of the userID.
Do you know what might be the problem? I updated the demo with all the new code.
Thank you!
On line 24, I removed the backgroundColor style setting. I moved the background setting to the video-player-container in page.tsx. This is because within the video-player-container, we internally create a canvas, and the video rendering occurs on this canvas. If its descendant elements have a background color, it will block the display of the video.
That fixed the render of the remote participant’s video but I’m still having problems when I toggle the video on and off a few times. If I toggle the video for the local participant, the video stops rendering and only shows a black video player, and if I toggle the remote participant, the video in the local participant’s page will show the last frame before the remote participant toggled the video off.
I update the demo so you can see the problem.
In useZoomVideo.tsx, within the toggleVideo method, I removed the call to mediaStream.detachVideo after stopVideo. Since both self-view and remote-view rendering use ParticipantContainer, there’s no need for an additional detach video here.
In ParticipantContainer.tsx, within the useEffect, you originally only handled the scenario where bVideoOn is true, but you missed the scenario where it’s false. Therefore, you need to call detachVideo to unbind the user from the video-player.