Client, server and limits¶
Where sound happens¶
Only clients render audio. The server holds instances and replicates them, but it never mixes, analyzes or plays anything. Each client builds and renders its own copy of the graph.
| Thing | On the server | On a client |
|---|---|---|
| Create audio objects or wires | Replicates to everyone (if in a replicated container) | Local to that player only |
AudioPlayer:Play() / Stop(), TTS Play() / Pause() |
Replicates; every client plays | Only that player |
| Property changes (volume, effect settings, curves) | Replicate | Local override, which the next server change to that property overwrites |
AudioAnalyzer levels and spectrum |
Always 0 / empty | Live |
AudioSpeechToText |
Doesn't run | Run it here, with the local mic |
AudioDeviceInput.Player, AccessType, SetUserIdAccessList |
Set them here | Only valid for Player = LocalPlayer |
AudioDeviceInput.Muted |
Mutes for everyone | Fine for the local player's own mic (push-to-talk) |
AudioDeviceOutput.Player |
Targets one player | — |
AudioPlayer.AutoPlay |
Not applied to replicated copies | Applies to players created or loaded locally |
VoiceChatService and DefaultListenerLocation settings |
Studio only | Studio only |
Choosing a side¶
- Server for anything everyone should hear the same way: world ambience, events, voice range, and effects on a player's voice that everyone should hear.
- Client for anything personal or high-rate: UI sounds, in-ear radio, underwater filters, visualizers, talking indicators, STT, and per-player TTS language.
- Mixed is normal: the server publishes state (attributes, remotes) and clients build the audio. The radio recipe works this way.
Don't wait on Ended or read IsReady / TimeLength on the server to time game logic. The server renders nothing. Use timers there, or let the client report back.
Limits¶
| Limit | Value |
|---|---|
AudioPlayer.Volume |
0–10 |
AudioFader, AudioDeviceInput, AudioTextToSpeech Volume |
0–3 |
| Attenuation curve size | 400 points per curve |
| TTS text | 300 characters per request |
| TTS throttle | 1 + 6 × CCU requests/min per experience, and 4/s per user on the client |
| STT utterance | 10 seconds per conversion |
| STT throttle | 1 + 5 × CCU requests/min per experience |
| More TTS/STT quota | Extended Services (paid) |
AudioRecorder (unreleased) |
60 s, no microphones |
| Analyzer spectrum | 0–24 kHz, empty for anything fed by a microphone |
| Voice | Voice-eligible (age-checked) players only; the player's own mic toggle wins |
Gotchas¶
Silent emitter or listener
Its parent must be an Attachment, Camera, BasePart or Model (or PositionType = Instance with a valid PositionInstance). Inside a Folder, it is silent with no error.
A listener that hears nothing
A listener needs a wire to an AudioDeviceOutput. Check its AudioInteractionGroup, because it only hears emitters with the identical string. With ListenerLocation = Default and no voice chat, no listener is created, so set it to Camera or Character.
Stop() doesn't rewind
AudioPlayer:Stop() freezes the playhead. Set TimePosition = 0 before Play() to restart. Ended doesn't fire on Stop(), so watch IsPlaying instead.
Hearing a sound twice
Fan-out means a source wired to both an emitter and an output plays twice: once spatial, once 2D. When you insert an effect, move the existing wire rather than adding a second path.
Cycles
A wire that would loop the graph shows Connected = false and passes nothing. Acoustic loops (listener → emitter that the same listener hears) aren't a graph cycle, so keep them apart with interaction groups.
StreamingEnabled
Emitters on parts that stream out are gone, and so is their sound. Put important emitters on persistent models, or on parts you know stay streamed in.
Respawns
Voice emitters are rebuilt on every CharacterAdded. Anything you changed on the old one (curves, inserted effects) must be reapplied.
Access lists are global
AudioDeviceInput allow and deny lists decide who receives the voice stream at all. Radio buses, analyzers and STT on another client are all subject to them.
Asset permissions
An AudioPlayer with an asset the experience isn't allowed to use never becomes IsReady. Use assets the experience owner uploaded, or ones shared with the experience.
Mixing old and new
Sound objects still play, but you can't wire them. Effects, analyzers and listeners don't see them. Migrate a sound before you try to process it.
Roblox-only properties
Echo cancellation, noise suppression, AGC and dictation flags on AudioDeviceInput / AudioSpeechToText are internal. They appear in API dumps but scripts can't set them.
Performance¶
- Effects run per client, per bus. Share buses: wire many sources into one effect instead of cloning effect chains per source.
AudioAnalyzer.SpectrumEnabled = falseis much cheaper. Leave it off unless you callGetSpectrum.- Large
AudioPitchShifter/AudioAnalyzerwindows add latency or CPU cost. - Acoustic simulation automatically scales with graphics quality. Turn off
AudioCanCollideon decorative clutter to cut the work. - Destroy one-shot graphs when done. A leaked
AudioPlayer+ emitter costs memory even when silent.