Audio (Wwise Runtime Design)¶
This page documents the current audio runtime design used by Visera.Runtime.Audio with Wwise backend integration.
Scope¶
- Backend: Wwise 2025.1.3 (regular
AK::SoundEngine::*APIs). - Threading mode: rely on Wwise internal audio thread (
bUseLEngineThread=true). - Engine-side scheduling: main-thread
Pump()+ priority queues + limiter/coalesce. - Primary target: VS-like gameplay with heavy unit and particle event bursts.
Why this architecture¶
- Keep backend execution in one place (Wwise internal queue/thread), avoid queue-on-queue complexity in phase 1.
- Let game systems submit commands concurrently through MPSC queues.
- Centralize overload handling (
Priority,Category, limiter, coalesce, aggregation) before backend calls.
Data flow¶
flowchart LR
GameSystems --> AudioAPI
AudioAPI --> ProducerLimiter
ProducerLimiter --> QCritical
ProducerLimiter --> QNormal
ProducerLimiter --> QSpam
QCritical --> Pump
QNormal --> Pump
QSpam --> Pump
Pump --> CoalesceAndAggregate
CoalesceAndAggregate --> WwiseBackend
WwiseBackend --> WwiseInternalThread
Runtime model¶
1) Priority queues¶
Audio commands are split into 3 MPSC queues:
CriticalNormalSpam
Producer threads enqueue directly into the corresponding queue.
2) Pump budget and fairness¶
Each tick, FAudio::Pump() drains queues with per-priority quotas:
Critical: guaranteed minimum budgetNormal: main throughputSpam: limited budget, can be dropped on pressure
When the frame is overloaded and spam backlog is high, spam commands are actively dropped first.
3) Command coalesce¶
Within one pump batch:
SetRTPC: same(object, rtpc)keeps only the last command.SetPosition: sameobjectkeeps only the last command.
This cuts redundant high-frequency updates dramatically in dense gameplay.
4) Impact aggregation¶
For non-critical impact events:
- bucket by
(eventID, spatialCell)in the same batch - keep strongest/intended representative command
This is aimed at particle-heavy collision bursts.
Interface layering¶
IAudioEngineuses backend-agnostic IDs:FObjectID,FEventID,FRTPCID,FPlayingID- Wwise backend performs local casts to
AkGameObjectID/AkUniqueID/AkRtpcID. - This avoids leaking Wwise-specific types into runtime interface.
Logging and observability¶
FAudio periodically reports:
- enqueued by priority
- dropped spam
- posted events
- coalesced RTPC/position counts
- impact aggregation count
- failed backend calls
- pending queue sizes
Config keys (current)¶
Audio.Pump.CriticalMinPerTickAudio.Pump.NormalMaxPerTickAudio.Pump.SpamMaxPerTickAudio.Pump.SpamDropPerTickAudio.Pump.MaxCommandsPerTickAudio.Queue.MaxPendingSpamAudio.Wwise.CommandQueueSizeBytes
Minimal gameplay usage¶
Assume soundbanks are already prepared in Assets/Sound.
// Acquire service
auto* Audio = Engine->GetAudio();
// Register emitters
auto bgmEmitter = Audio->RegisterEmitter(FName{"BGMEmitter"}, FAudio::EPriority::Critical);
auto playerEmitter = Audio->RegisterEmitter(FName{"PlayerEmitter"}, FAudio::EPriority::Critical);
// Startup BGM
Audio->PostEvent(FName{"Play_BGM_Main"},
bgmEmitter,
FAudio::ECategory::Ambient,
FAudio::EPriority::Critical,
1.0f,
0);
// Per-frame (main loop)
Audio->Tick();
// Collision SFX (example trigger)
Audio->PostEvent(FName{"Play_SFX_Hit"},
playerEmitter,
FAudio::ECategory::Impact,
FAudio::EPriority::Normal,
1.0f,
0);
SoundBank layout and loading¶
Banks are loaded at bootstrap. Expected layout:
Assets/SoundBank/Main/— base path for banks (configurable viaAudio.Bank.BasePath)Init.bnk— initialization bank (loaded first)Main.bnk— main bank with events
Config keys:
Audio.Bank.BasePath— base path for bank resolution (default:Assets/SoundBank/Main)Audio.Bank.Init— init bank name (default:Init.bnk)Audio.Bank.Main— main bank name (default:Main.bnk)
Naming recommendation (Wwise side)¶
For the minimal loop above, keep at least:
- Event:
Play_BGM_Main - Event:
Play_SFX_Hit
Add RTPCs later only when needed for dynamic mix/intensity.
Next steps¶
- Add hot-reload for audio config thresholds via
OnConfigChange. - Add JavaScript-safe audio scripting facade (command submission only).
- Add component lifecycle helpers for pooled entities.