# Voice chat in a Glop Voice is optional. Glop owns microphone capture, playback, WebRTC connections and the consent UI. An uploaded game gets status, participant identities and speaking indicators; it never receives microphone streams, audio buffers, network addresses, signaling messages or relay credentials. ```js import {createGlop} from './glop-sdk.mjs'; const glop = createGlop(); const voice = await glop.voice.enable({ channel: 'lounge-v1', onState(state) { // phase: 'off', 'joining', 'on', or 'error' // muted, error, relayAvailable // participants: [{playerId, name, connected, muted, speaking}] renderVoiceStatus(state); } }); joinButton.onclick = () => voice.requestJoin(); muteButton.onclick = () => voice.mute(); leaveButton.onclick = () => voice.leave(); ``` `enable()` waits until the Glop is active and adds Glop's trusted **Join voice** control. It does not prompt for or open the microphone. `requestJoin()` opens a confirmation dialog and resolves immediately; use `onState` for the actual connection result. Only a real click on Glop's confirmation can start capture. The browser also requests microphone permission when necessary. Games can mute or leave voice. They cannot silently unmute it: unmute requires a real click in Glop's own controls, or a fresh confirmation after `requestJoin()`. Glop keeps **Mute / Unmute**, **Leave voice** and the microphone status outside the uploaded frame. The frame's microphone Permissions Policy remains disabled. Voice rooms are scoped to **Glop project + voice channel**, separate from ordinary shared rooms. Up to eight active participants can join one room. `playerId` is the same account-scoped identity used by shared-room peers, so games can draw speaking indicators above the correct avatar. It is not a raw account ID. Multiple tabs may join as separate participants; avoid joining twice on one device to prevent echo. After you join, voice continues when you switch tabs or focus another window, while the uploaded game's graphics and scripts pause. Leaving voice, leaving the Glop, closing the page, losing the microphone or losing authenticated signaling stops the microphone tracks and peer connections. Returning after leaving does not automatically reconnect or reopen the microphone. Browsers or operating systems that suspend a page entirely can still interrupt a call. Draft previews cannot join voice; publish first. Voice media travels through browser WebRTC connections, not through the game's scripts or Glop's database. Glop stores only short-lived signaling events using the existing bounded room service. Voice is limited to audio: video and data-channel session descriptions are rejected. Other participants can still record what they hear outside Glop; this SDK is not a recording-prevention system. ## Connectivity and TURN The default configuration uses Google's public STUN service and direct browser connections. Direct connections expose network addresses to other voice participants and may fail across restrictive Wi-Fi, corporate firewalls or some mobile networks. A successful same-network browser test does not prove connectivity on all networks. For reliable relay connectivity, configure the **Sites runtime secret** `VOICE_ICE_SERVERS` with a JSON array of TURN configurations supplied by your relay provider: ```json [ { "urls": ["turn:turn.your-domain.com:3478?transport=udp", "turns:turn.your-domain.com:5349?transport=tcp"], "username": "provider-issued-username", "credential": "provider-issued-credential" } ] ``` Use a provider-issued, restricted TURN credential; rotate it according to the provider's policy. Do not put credentials in a Glop bundle, client source file or `glop.json`. The backend returns the configuration only to authenticated, authorized host voice connections. The trusted host necessarily receives TURN credentials; the uploaded iframe does not. The operator must provision the TURN service separately and deploy after setting or changing the runtime secret. Without a configured relay, Glop reports direct-connection failures instead of claiming that everyone can hear each other. `relayAvailable` means a relay is configured, not that a particular network path has been verified. TURN-provider bandwidth limits and billing are separate from Glop hosting. ## Verification `tests/voice.mjs` covers consent, origin and account checks, publication isolation, voice/shared-room separation, audio-only signaling, capacity and revocation. `tests/voice-browser.mjs` uses generated microphone audio in two independent local browser sessions to verify actual WebRTC transmission and decoded audio energy, mute/unmute, direct iframe capture denial, synthetic-click denial, background audio continuity, track shutdown, and late-permission cancellation. It does not access the operator's real microphone.