Voice
A room already has everyone in it. Voice adds their microphones:
import { joinRoom, joinVoice } from '@irtio/client';
import { schema } from './irtio/schema';
const room = await joinRoom(schema, { room: code });
const voice = await joinVoice(room); That is the whole API for the common case. The browser asks for microphone permission, everyone in
the room who has also called joinVoice can hear each other, and everyone who has not carries on
playing with no idea it happened.
voice.mute(true); // stop sending; you can still hear
voice.muted; // what you last set
voice.peers; // client ids currently in the call
await voice.leave(); // tear down; the game socket is untouched joinVoice takes the room, not a room code, because it rides the room’s existing connection. There
is no second URL, no second token, and nothing new to configure.
Where the audio goes
Audio does not travel between players directly. It goes to a small server on the same machine as your room — an SFU, one per game box — which forwards each person’s audio to everyone else.
That is the difference between a call that works with two people and one that works with eight. In a direct peer-to-peer call, every participant uploads their microphone once per other participant, so a group of eight has each person uploading seven copies of themselves. Through an SFU each person uploads once. On a home connection that is the difference between a group call and a slideshow.
It also means audio never leaves the region the room is in.
What it costs
Two things are counted, and they behave differently on purpose.
Voice minutes are participant-minutes: one minute of one person holding a seat in a call. Four people in a ten-minute call is forty voice minutes, not ten. The clock starts when someone joins the call and stops when they leave, close the tab, or lose their connection.
A muted participant still uses voice minutes. Their seat is still held and the server is still carrying everyone else’s audio to them, so the cost to us does not change when a microphone does. What mute does change is data out: a muted participant sends nothing, so their upload stops immediately.
Voice data out is counted under your normal data-out meter, marked as voice, so your bandwidth is one number rather than two you have to add up.
You can see both on the usage page and from the CLI:
irtio usage A project that has made no calls shows voice as having no usage rather than as zero, because those are different facts.
What it does not do yet
- Positional audio is not in this release.
joinVoice(room, { positional: true })is accepted and currently does nothing but warn. Everyone is heard at the same volume regardless of where they are in your world. - No video and no screen sharing. Audio only.
- NPCs and bots have no voice. They have no microphone, they are never given a seat in a call, and they never produce voice minutes.
- One region per call. Everyone in a call is served by the same box, which is the box the room is on.
Signaling and your room code
Setting up a call needs a short exchange of connection details between each browser and the SFU.
That exchange rides the same socket as your game, but your room code never sees it: the
platform intercepts voice messages before your handlers run, and your onMessage is never called
with them. A room also cannot fabricate voice messages, because the addressing value that marks
one is not something room code can express.
The practical consequence is that you do not have to write a signaling handler, and you cannot
accidentally break voice by returning false from onMessage.
Worth knowing about what does travel: connection details are per-call and per-project. A room’s own code is yours and is assumed to be able to do anything it likes to your own game — the same stance as your JWT signing keys. No platform credential is ever part of a voice exchange, and the SFU itself holds no credentials at all.
Availability
Voice is switched on per region. Where it is off, joinVoice rejects with a clear error rather
than hanging, and the rest of the room is unaffected.