Building a telehealth waiting room with Zoom Video SDK
In some industries—for example, telehealth, where a Video SDK session may be between a doctor and a patient—it can be useful to have a waiting room, or main lobby, where all patients enter before they visit with the doctor.
To create a waiting room experience, there are a variety of options, ranging from long-polling an internal API, to creating a bidirectional websocket layer that sits between your application and Zoom's Video SDK. However, for this article, we're going to look at how you can accomplish the same result without building any new APIs, completely relying on Video SDK sessions and subsessions (sometimes referred to as "breakout rooms").
Getting started
Before creating any subsessions, you'll first need a JWT token for the host1 (in our case, the doctor) that is used to create and join the main session.
Once the doctor has joined the main session, your application will have access to the VideoClient namespace, which, by calling getSubsessionClient(), will give access to the underlying SubsessionClient namespace.
const subsessionClient = client.getSubsessionClient();
Initializing a subsession (patient) room
If we're thinking about the main session as a doctor's office lobby (or waiting room), then we can think of subsessions as patient rooms, where the doctor and patient are given access, as well as anyone else who may be part of the visit, such as a family member.
To create a patient room, the Video SDK comes with a createSubsessions() function that can be used to create new subsessions. This function takes two arguments: data and, optionally, pattern. data refers to the number of rooms that you wish to create (or the names of the rooms you'd like to create), and pattern refers to whether participants in the main lobby should get automatically assigned to a room.
For our use case, the SDK can automatically name the subsession, and we will manually pre-assign the participants. (As pattern is not a required argument, and will default to manual assignment, we will omit it in the following function call.)
const subsessionsOrError = await subsessionClient.createSubsessions(1);
if (subsessionsOrError instanceof Error) {
throw subsessionsOrError;
}
const subsession = subsessionsOrError[0];
Note that in the code snippet above, we create a variable subsessionsOrError. This is because createSubsessions() will return a Promise<Array<Subsession> | Error>, so we'll first confirm it's not an error. If it isn't, we extract the Subsession object of the first subsession in the array, since it's the only subsession created.
Assigning the patient and doctor to the subsession
Once the subsession has been created, as the host, we'll assign the participants to the room. At the very least, we'll assign the patient and the doctor; however, if the patient has family members that would like to be present, this is where they will be assigned as well.
const currentParticipant = client.getCurrentUserInfo();
const otherParticipant = client
.getAllUser()
.find((participant) => participant.displayName === "John");
if (otherParticipant) {
subsession.userList.push(currentParticipant, otherParticipant);
}
For the code snippet above, we find the user with the displayName that is equal to "John," but in a production application it's recommended to display a drop-down that the doctor would select from, which you would use to fetch the patient's Participant object.
To pre-assign our participants to the subsession, before the subsession is opened we will push the Participant object(s) that we wish to assign by adding them to the subsession's userList property.
Opening the subsession room
Once the participants have been pre-assigned to the subsession, it can be opened by executing the openSubsessions() function.
await subsessionClient.openSubsessions([subsession], {
isAutoJoinSubsession: true,
waitSeconds: 0,
});
In the code snippet above, we pass in the subsession that we wish to open (which was defined a previous section), as well as two optional properties:
isAuthJoinSubsession, which automatically moves participants to the subsession when opened. This is set to true as our participants were pre-assigned to the subsession.waitSeconds, which defines the amount of time (in seconds) that elapses before the subsession is closed whencloseAllSubsessions()is called. This is set to 0 so the subsession will immediately close.
Starting the conversation
When a participant moves between the main session and a subsession, the SDK will fire the user-updated event. If the participant moved into a subsession, the subsessionId property will be present.
Once the doctor and patient (and any other participants) have joined the subsession, we can begin the conversation by prompting camera and microphone access, as well as rendering the video feeds to the screen.
client.on("user-updated", (payload) => {
for (const participant of payload) {
if (participant.subsessionId) {
// TODO: Start audio and video for participant
// TODO: Render participant video feed to screen
}
}
});
Wrapping up the patient visit
When the patient visit is over, the subsession room can be closed, automatically moving all participants back to the main session, by calling the closeAllSubsessions() function.
Assuming the patient is no longer needed in the session, it's recommended to remove them2, redirecting them to another page on your application, such as a thank you or summary page.
if (await subsessionClient.closeAllSubsessions()) {
await client.removeUser(otherParticipant.userId);
}
Conclusion
As demonstrated in this blog post, Zoom's Video SDK is a powerful, developer-friendly video conferencing provider, allowing the creation of custom user experiences, whether that's for one-on-one video calls, or building a complete waiting room experience!
For more information on subsessions, check out our developer documentation.
Footnotes
-
Although Video SDK requires host permissions to create and manage subsessions, participants can still join the session before the host, waiting in the main lobby. ↩
-
It's imperative to note that the participant must be in the same session as the host in order to execute the
removeUser()function. ↩