Build video calls
A Video Room is a Resource that several people join at once, each with a camera and microphone. Start by creating a room and joining it from two browser tabs, then add controls for the microphone and camera, camera choice, screen sharing, the layout, and the participant list, and finally let phone callers join the same room.
Pick the right product for video calls
The Browser SDK carries the video. The REST API, usually through the Server SDKs, creates the room and issues the token the browser signs in with. SWML and Relay bring phone callers in by audio.
- SWML is a document of call instructions that SignalWire runs. Its
join_roommethod puts the caller in a room. - WebSocket (Relay) is a Relay client in the Server SDKs. It holds a WebSocket open from your server and can move a live call into a room from your code.
- The REST API creates and configures Video Rooms, lists their addresses, and issues tokens. The Server SDKs wrap each of these requests.
- The Browser SDK puts a person in the room from a web page, with their camera, microphone, screen, and in-call controls.
Prepare for video calls
Have these values ready:
- Your Space URL, such as
<YOUR_SPACE>.signalwire.com. - Your Project ID and API token from the Dashboard’s API credentials page. Enable the token’s Video permission, and Voice if you bring in phone callers over Relay.
- A web page you can serve over HTTPS or
localhost, and a browser with a camera and microphone. - To bring in phone callers, a voice-capable phone number in your Space and a phone to call it from.
A page served over plain HTTP from any other host can’t use the camera or microphone, so it can’t
join the room with them. Serve the page over HTTPS, or open it from localhost while you develop.
For audio calls between two people rather than a shared room, see Make and receive calls. If you have a page built on Browser SDK v3 and room tokens, Migrate from v3 maps it to the flow on this page.
Replace these values in the samples you run:
Join your first video call
Three things put a browser in a room. The Video Room is the Resource, and SignalWire gives it an
address when you create it. Your server issues a guest token for
that address. The page signs in with the token and dials the address. SignalWire composes every
participant’s video into one stream and sends the same stream to everyone, so the page shows the
whole room in a single <video> element.
Create a Video Room
Run this program once on your server. It creates the room and prints its id, the Resource ID
you use in the next step. Room names are unique in a project, so a second run with the same name
fails.
The cURL request calls Create conference room. The REST API reference calls a Video Room a conference room; it’s the same Resource.
To create the room in the Dashboard instead, open Resources, select Add, and choose
Video Room. Enter a Room Name, choose Build From Scratch so the room has no prebuilt
interface, and select Create. Then find the room’s id with
List conference rooms.
Issue a guest token for the room
Run this program on your server once for each browser tab you want in the room. It looks up the
room’s address and issues a guest token for it, then prints both. Paste the address in place of
<YOUR_ROOM_ADDRESS> in the page in the next step, and keep the tokens for the tabs.
The cURL requests call List Resource Addresses, then Create Subscriber guest token.
The room address looks like /public/team-standup?channel=video. Copy it from the output rather
than building it from the room name: SignalWire names the address after the room’s display name,
and adds a suffix when that name is already taken.
A guest token is issued for the addresses you list in allowed_addresses, up to 10, and lasts two
hours by default. It places calls only, which is all a room page needs. To sign people in as
Subscribers instead, or to issue tokens from your backend each time a visitor opens
the page, follow the authentication guide.
Run the room page
Load this script on a page served over HTTPS or localhost, with the elements listed in its
comments. The page signs in with the token you paste, dials the room address, and shows your
camera beside the room.
dial() sends your camera and microphone with video: true and audio: true, and
receiveVideo: true asks for the room’s video in return. The channels.video address ends in
?channel=video, which turns on all three by itself. Keeping the options explicit means the page
still receives the room’s video if it dials the address without that suffix, where receiving video
is off by default. DialOptions lists every media option.
The local preview is muted so you don’t hear yourself. #room-video isn’t, because it also
carries the room’s mixed audio.
Join from two tabs
Paste a guest token, select Join, and allow camera and microphone access. Your camera appears
in #local-video, and #room-video shows the room with you in it. Open the page in a second tab,
paste the second token, and select Join. A tone plays as the second participant enters, and
both tabs show both participants in the room video. Select Leave in each tab when you finish.
Two tabs on one computer play each other’s audio back into the microphones, so mute one tab or wear headphones while you test.
If it doesn’t work, check the symptom:
- The browser never asks for the camera. Serve the page over HTTPS or
localhost, and check that the site isn’t blocked from the camera in the browser’s settings. dial()rejects withCallCreateError. The token doesn’t reach the address. Check that the page dials thechannels.videoaddress printed with the token, and that the token is for this room.- Your camera shows, but the room video stays black. Check that the page dials the
channels.videoaddress, or keepsreceiveVideo: truein thedial()options. - Joining worked earlier and now fails. The guest token expired after two hours. Issue a new one and reload the page.
The Browser SDK troubleshooting guide covers permissions and media problems in more depth.
Mute and unmute your microphone and camera
Muting is a control on your own participant, call.self, not on the call. A muted participant
stays in the room, and the other participants see their state change.
Mute and unmute from a browser
Add two buttons to the page from Join your first video call, then
add the lookups and the handlers below. toggleMute() mutes or unmutes your
microphone, and toggleMuteVideo() turns your camera off or on in the room.
call.self$ emits once you’ve joined the room, and again each time your participant changes, so
switchMap keeps exactly one subscription to each state. Disable both buttons again in the
page’s status$ handler when the call ends. The Browser SDK call controls guide
adds deafening, hand raising, and keypad tones.
Switch cameras during a video call
The browser can list every camera it can use, and the page can switch between them without leaving the room.
Pick a camera from a browser
Add a picker to the page, then add these lines inside the if (!client) block, right after the
client is created. videoInputDevices$ emits the camera list, and
selectVideoInputDevice() switches to the one you pick, including on a call
already in progress.
Browsers hide camera names until the page has camera access, so the labels fill in after the first Join. The Browser SDK device management guide adds microphones, speakers, and devices plugged in mid-call.
Share your screen in a video call
A screen share joins the room as its own participant, and SignalWire composes it into the room video beside the cameras.
Share your screen from a browser
Add a button to the page, then add the lookup and the handlers below.
startScreenShare() opens the browser’s screen picker, and
screenShareStatus$ reports none, starting, started, or stopping.
If the share fails, your camera and microphone stay in the room. The Browser SDK screen sharing guide covers sharing audio with the screen and checking whether a participant may share.
Change the video room layout
The layout decides how SignalWire arranges participants in the room video. Every participant gets the same composed stream, so a layout change applies to everyone in the room.
Change the layout from a browser
Add a picker to the page, then add the lookup and the handlers below. layouts$ emits
the names of the layouts the room offers, layout$ emits the current one, and
setLayout() switches to another.
The second argument to setLayout() can also move specific participants into positions in the
layout. An empty {} changes only the layout. The Browser SDK layouts guide covers participant
positions and drawing overlays on the room video.
Set the default layout via REST
Set layout on the Video Room to choose the layout participants see when they join, before anyone
changes it. A new room uses grid-responsive. The other values are grid-responsive-mobile,
highlight-1-responsive, 1x1, 2x1, 2x2, 5up, 3x3, 4x4, 5x5, 6x6, 8x8, and
10x10.
The cURL request calls Update conference room, which also changes the room’s
video quality, participant limit, and most of the other settings. A room’s name can’t be changed
after you create it.
Show who is in a video call
The page can list everyone in the room, including you and any screen share, and keep the list current as people join, leave, and mute.
List participants in a browser
Add a list to the page, then add the lookup and the subscription below.
participants$ emits the whole list each time someone joins, leaves, or changes
state, so the page redraws it from scratch.
Clear the list in the page’s status$ handler when the call ends.
Track and leave a video call
The call’s status tells the page when you’re in the room and when you’ve left it, whether you selected Leave or the call failed.
Track the call and leave from a browser
hangup() takes you out of the room and leaves everyone else in it. The call then moves
to disconnecting and on to destroyed. A call that fails moves to failed. With
disconnected, failed, and destroyed treated as final, the page’s one status$
subscription resets it for every outcome. To show the status, add <p id="status">Idle</p> to the
page, then add the lookup below and replace the page’s status$ subscription:
The status shows connected while you’re in the room. After Leave, select Join again to
rejoin with the same token.
Let phone callers join a video room
A phone caller joins the same room by audio. Browser participants hear the caller, and the caller
hears the room. To put a caller in the room, the call handler on your phone number runs
join_room with the Video Room’s name: the name you created it with, such as team-standup,
not its address. For a room created in the Dashboard, read conference_room.name from
List conference rooms.
If no room has the name you pass, join_room creates one, and the caller waits alone in it. Copy
the name exactly as you created the Video Room.
Let phone callers join via SWML
Run either server below, or host the YAML document as a SWML Script. Then give it a public URL and
assign the script to your phone number, as Answer a call via SWML shows.
join_room answers the call itself and sets join_room_result to joined or
failed.
With a browser tab in the room, call your number from your phone. The tab plays the entry tone, the caller appears in the participant list, and you hear each other. If the tab never hears the caller, check that the number’s Inbound Call Settings point at this script and that the name matches the Video Room’s. In a trial project, call from a verified number, as Prepare for your first call describes.
Let phone callers join via WebSocket (Relay)
Run either handler below and leave it running. It subscribes to the video-room topic, answers
each call, and moves it into the room. Assign a Relay Application for that topic to your phone
number, as Answer a call via WebSocket (Relay) shows.
Test it the same way as the SWML version. To take the caller out of the room while keeping the call, have the handler leave the room with the Server SDKs Relay client instead of hanging up.
Examples
Build a room page with every control
This page combines the first run with every browser task above: mute buttons, a camera picker, screen sharing, a layout picker, a participant list, and a status line.