Skip to content
DEV505 / Sound ManagerDOCUMENTATION

DEV505 / API REFERENCE

SoundBus

The entry point for playing and controlling sound through the active Sound Manager.

Declaration
namespace DEV505.SoundManager
{
public static class SoundBus
}

New to the terms on this page? An event is a saved sound recipe, a play is one running copy, and a handle is the value you keep to control that copy. Start with Your first sound for a complete script and scene setup. The blocks below are reference signatures or labeled excerpts, not separate scripts to attach to objects.

Add the event to the active manager’s Direct events or Libraries list before Play Mode. Call this API on Unity’s main thread, for example from Start, Update, or a button callback. Commands dispatched from a worker thread to the built-in service return InvalidContext. Query helpers are not safe to call from a worker thread either.

A missing manager returns NoManager from dispatch/play and logs a warning once per play session. It does not buffer requests until a manager appears. An existing manager may admit a play as Queued while clips prepare or while a request waits for the current tick to finish.

Overloads
public static SoundPlayResult Play(
SoundKey key, in SoundPlayContext context = default);
public static SoundPlayResult Play(SoundKey key, Vector3 position);
public static SoundPlayResult Play(SoundKey key, Transform follow);
public static SoundPlayResult Play(
SoundEvent sound, in SoundPlayContext context = default);
Argument Meaning
key The registered name of the event. Prefer generated Sounds.* values. An unknown key gives NotRegistered.
context Optional per-play position/follow target, owner, initial overrides, seed, and delay. A default context has no follow target or owner and uses its zero position.
position Fixed world point. The sound remains there if the object that caused it moves away.
follow Transform tracked while the play runs. This convenience overload also owns the play by follow.gameObject.
sound An event asset reference. It still needs registration on the active manager, and the same validation and preparation rules apply.

Returns SoundPlayResult: Status describes admission and Handle identifies an accepted play. Accepted is true for both Accepted and Queued. An accepted request is not a guarantee that a voice is already audible or that the play can never subsequently fail.

Fixed position and an initial parameter · excerpt
var context = SoundPlayContext.At(footPosition)
.With(SoundParameters.Footstep.Surface, 1); // Stone in this graph
var result = SoundBus.Play(Sounds.Footstep, context);

This excerpt requires a registered Footstep event and a Vector3 footPosition. Initial overrides are applied before On Start, so the first branch sees the intended surface. The scene’s surface enum has a different numbering; map it to the graph value rather than casting directly.

Follow with explicit ownership and initial intensity · excerpt
var service = SoundServices.Current;
if (service == null)
return;
var owner = service.OwnerOf(gameObject);
var context = SoundPlayContext.Following(transform, owner)
.With(SoundParameters.Campfire.Intensity, 0.35f);
var result = SoundBus.Play(Sounds.Campfire, context);

This belongs inside a MonoBehaviour method. Keep the accepted handle if you need later control. .Following(transform) by itself does not acquire the same automatic GameObject owner as Play(key, transform); pass an owner when constructing the context if you need owner-wide commands. A destroyed follow target is also handled by the event’s loss policy.

.With(...) returns a new struct value. Keep the returned context; calling it without assigning/chaining discards the override. Up to four inline overrides are supported. More require TypedParameters or an appropriate service API. Float-array overrides apply first, then typed-array overrides, then inline values.

The complete Campfire component shows accepted-result handling and cleanup.

Stop one play
public static bool Stop(SoundHandle handle, float fade = 0.1f);

handle identifies the play; fade is seconds and must be finite and non-negative. Returns true when the service accepts the stop, false for a missing manager, invalid/stale target, or invalid request.

For a started play, stopping runs On Stop, then fades remaining pre-existing voices. Voices created by the stop branch can continue as release audio. A node explicitly stopped through its graph Stop port uses that node’s authored fade-out. A queued play that never started is cancelled without a normal started-play release. The return value does not mean all audio is now silent.

Request a graceful ending · excerpt
SoundBus.Stop(fire, fade: 0.15f);

Here fire is a handle retained from a previous accepted play. Do not assume changing this fallback fade changes the duration of every authored release cue.

Stop plays owned by an object
public static int StopAll(UnityEngine.Object source, float fade = 0.1f);

Returns the number of plays reached through that object’s existing owner token. Zero means no eligible plays were reached, including when no manager or owner exists. The method does not create an owner record merely to perform a no-op. It uses the same stop/fade semantics as per-handle stop.

Use the same owner identity · excerpt
// Play(key, transform) uses the transform's GameObject as owner.
SoundBus.Play(Sounds.Campfire, transform);
// Later:
int stopped = SoundBus.StopAll(gameObject);

Pass gameObject for that convenience play, not an unrelated component. A context with an explicit different owner must be addressed through that owner’s identity/service methods.

Overloads
public static bool SetFloat(
SoundHandle handle, SoundParameterId parameter, float value);
public static bool SetFloat(
SoundHandle handle, string name, float value);
public static int SetFloat(
UnityEngine.Object source, string name, float value);

Sets a live float parameter’s target. Prefer the generated parameter ID for repeated writes; string overloads match by name. Declared numeric ranges clamp accepted values, and the graph parameter’s rise/fall rates determine smoothing. A wrong type, missing parameter, non-finite value, or dead target is refused.

Per-handle overloads return whether the update was accepted. The source overload returns how many owned plays accepted it. A false/zero result does not reveal a detailed rejection reason through this shortcut.

Change crackle volume · excerpt
SoundBus.SetFloat(fire, SoundParameters.Campfire.Intensity, 0.35f);

Campfire’s initial branch and ignition may already have run by this point. Use the play context for values required during On Start.

Typed live update
public static bool SetParameter(
SoundHandle handle, SoundParameterId parameter, SoundValue value);

Sets a declared parameter with an explicit type. Returns whether the service accepted the update. The type must match; audio-asset values must be among the event’s allowed assets. Numeric values are subject to the declared range. This method does not add a new parameter to a graph.

Select an integer tool · excerpt
SoundBus.SetParameter(workshop, SoundParameters.Workshop.Tool,
SoundValue.Int(2)); // Drill

This excerpt assumes workshop is the retained handle of a running Workshop event. Use SoundValue.Float, .Int, .Bool, or .Asset for the declared type. Initial typed values can also be passed through SoundPlayContext.With before playback begins.

Overloads
public static bool SendSignal(SoundHandle handle, SoundSignalId signal);
public static bool SendSignal(SoundHandle handle, string signal);
public static int SendSignal(UnityEngine.Object source, string signal);

Queues a named graph action on existing plays. It does not start another play. The per-handle forms return whether the signal was accepted; the source form counts plays that accepted it. A missing signal, ended or stopping play, or full signal queue gives false/zero. The graph processes an accepted signal on the next service update; the call does not promise a recording has already started.

Engine horn · excerpt
SoundBus.SendSignal(engine, "Horn");

engine must identify a running Engine event. For repeated calls, resolve the ID once from its event with SoundEvent.GetSignalId("Horn"), check IsValid, then use the ID overload. Campfire has no signal entry points in its current graph.

Query liveness
public static bool IsAlive(SoundHandle handle);

Returns whether the active service still owns this play. Returns false for a default, finished, stale-session, or stale-generation handle, or without a manager. A queued or stopping play can remain alive while it still exists. Liveness is not the same as audibility, and SoundHandle.IsValid alone is not a liveness test.

Prevent another active loop · excerpt
if (SoundBus.IsAlive(fire))
return;
Pause or resume one play
public static bool SetPaused(SoundHandle handle, bool paused);

Returns whether the request was accepted. true pauses that play; false resumes it. Per-play pause is separate from service/listener pause. Resuming a play does not override an applicable global pause. Missing or dead targets return false. If your interaction retains two plays—for example, a crossfade—address both handles.

Pause a retained play · excerpt
SoundBus.SetPaused(fire, true);
// Later:
SoundBus.SetPaused(fire, false);
Look up registered content
public static bool TryResolve(SoundKey key, out SoundEvent sound);

Returns true and the registered event when the current manager resolves the key. Otherwise returns false with sound set to null. Useful for content validation or resolving a signal ID; Play(key, ...) already performs the lookup itself. Successful resolution is not a play request and does not imply a voice is running.

Resolve a signal once · excerpt
if (SoundBus.TryResolve(Sounds.Engine, out var eventAsset))
{
var horn = eventAsset.GetSignalId("Horn");
if (horn.IsValid)
SoundBus.SendSignal(engine, horn);
}
Send a request explicitly
public static SoundPlayResult Dispatch(in SoundRequest request);

All the command shortcuts above route through dispatch. Use it when code already works with SoundRequest values, or when you want a status instead of a shortcut’s bool/count. It supports play, stop, owner-wide stop, parameter, signal, pause, and resume requests.

Inspect a stop result · excerpt
var request = SoundRequest.Stop(fire, 0.15f);
var result = SoundBus.Dispatch(request);
Debug.Log(result.Status);

For control requests, Accepted means at least one target was reached; otherwise the bus commonly reports NoTarget. Individual service validation failures may be collapsed into NoTarget by these control shortcuts. Do not assume every false parameter/stop result gives the exact underlying cause through dispatch. An off-thread dispatched request against the concrete service reports InvalidContext.

Shared notification channel
public static SoundNotifications Notifications { get; }

Use Subscribe(Action<SoundNotification>) and dispose its returned token when the listener is disabled/destroyed. Subscribing through the bus follows replacement of the active service. It reports admission/start/termination from all plays, so filter by the relevant handle/event instead of treating every notification as yours.

Lifecycle subscription · excerpt from a component
private System.IDisposable subscription;
private void OnEnable()
{
subscription = SoundBus.Notifications.Subscribe(notification =>
{
if (notification.IsTerminal)
Debug.Log($"{notification.Kind}: {notification.Reason}");
});
}
private void OnDisable()
{
subscription?.Dispose();
subscription = null;
}

This excerpt observes every ending, cancellation, and failure, including other objects’ sounds. Subscribe(null) throws ArgumentNullException; duplicate delegates are not added twice. Do not add a second OnDisable method to the complete Campfire recipe—combine cleanup into its existing method. The built-in service delivers notifications at the end of its update; subscribe before playing, then save the returned handle. The complete Engine example shows how to filter messages for one play.

Status Meaning
Accepted Started/admitted immediately, or a control command reached a target.
Queued Admitted for a later tick or clip readiness. result.Accepted is still true.
NoManager No active playback service; nothing is buffered.
NotRegistered No matching registered key/event.
InvalidEvent Invalid graph or runtime graph failure.
NotReady Service shut down, or startup wait expired.
MissingClip Required clip is absent or failed to load.
ConcurrencyLimit Event instance limit refused/replaced a play.
CapacityExceeded No available slot, start-queue room, or voice.
InvalidContext Invalid position/delay/owner/parameter or dispatched call from another thread.
Cooldown The event was requested again too soon.
NoTarget The control request did not reach a live eligible play.

A playback result reports admission; later failures and cancellations are reported through notifications. Every status above comes from the current enum, not a planned API.

Try the complete lifecycle recipe or follow the Campfire graph walkthrough.