Skip to content

Audio state

Some hosts render their own sound and music buttons around the game. The frvr.com game page is the first: its toggles sit outside the game’s iframe. FRVR.audio tells the game what those toggles say, so it can follow them instead of showing a second set.

This is separate from the lifecycle audio hooks. onAudioSuspend / onAudioResume stay required on every channel. FRVR.audio adds the split between music and sound effects on hosts that have one.

FRVR.audio is undefined on channels without host audio controls. Where it exists, isAvailable() settles once, after a handshake with the host:

const audio = FRVR.audio;
if (audio && await audio.isAvailable()) {
  hideOwnAudioControls();
  applyAudioState(audio.getState());
  audio.addListener(applyAudioState);
} else {
  showOwnAudioControls();
}

false means the host isn’t driving audio this session, so the game keeps its own controls.

const { music, sound } = FRVR.audio.getState();
// true = audible

getState() returns { music: true, sound: true } until the host reports otherwise, and is accurate from the moment isAvailable() resolves true. A host with a single mute button reports the same value for both flags.

function applyAudioState({ music, sound }) {
  mixer.music.setMuted(!music);
  mixer.sfx.setMuted(!sound);
}

FRVR.audio.addListener(applyAudioState);
// later
FRVR.audio.removeListener(applyAudioState);

The host’s state overrides the saved preference

Section titled “The host’s state overrides the saved preference”

While the host drives audio, its state wins in both directions. If the player muted the game in an earlier session and the host says unmuted, the game plays sound, and the reverse.

Apply the host’s state as a temporary override. Don’t write it into the player’s saved sound settings: on a channel without host controls, the game’s own setting applies again.

They still get muted. When the host turns both music and sound off, the SDK calls FRVR.lifecycle.onAudioSuspend(), and it calls onAudioResume() once either comes back on. Turning off only one of the two doesn’t reach the lifecycle hooks, so a game needs FRVR.audio to honour the split.

The same flag is published as FRVR.channelCharacteristics.hasNativeAudioControls, for code that only needs to decide whether to draw the buttons.

MethodPurpose
isAvailable()Resolves true when the host drives the audio state. Settles once.
getState()Current { music, sound }. true means audible.
addListener(fn)Call fn(state) on every change the host makes.
removeListener(fn)Remove a listener added with addListener.