Skip to content
Documentation
Download
English

Command reference

Send each command as a separate JSON text message over an authenticated WebSocket connection. Start with the connection guide if you have not received your first state yet.

All field names are case-sensitive. Replace example IDs with values from your latest state. The server applies the same playback rules, locks, and feature access as the app. Use subsequent snapshots to confirm the result; a successful send is not an acknowledgement that a command ran.

Command Purpose
{"type":"request_state"} Request a fresh full snapshot, for example after losing local state. Routine polling is unnecessary.
{"type":"ping"} Receive {"type":"pong"} if hello_ok.features includes ping.
{
"type": "play_playable",
"playable_id": "playable-id",
"action": "start",
"next_volume": 70,
"next_pan": 0
}

playable_id is required and comes from project.categories[].playables[].id. A playable is a project button, such as a sound, video, image, or instruction. Launching it can create a player with a different runtime ID.

Optional field Meaning and default
action Launch action below; defaults to start.
next_volume Integer display percentage, 0–100. Defaults to control.next_sound_volume.
next_pan Pan percentage, -100 (left) to 100 (right). Defaults to 0 (center).
Action Behavior
start Start the playable using its configured playback behavior.
fade_in Start with a fade-in.
crossfade Start with the app’s crossfade action.
replace Start with the app’s replace action.
toggle Stop matching active players, or start if none are active.
toggle_fade Fade out matching active players, or start if none are active.

Action behavior depends on the playable type and its configuration. The WebSocket launch command has no output-device field; use the configured routing and output selection in Sound Show.

{ "type": "stop_all" }
{ "type": "fade_out_all", "duration_ms": 1500 }

These affect unlocked sound and visual players. stop_all stops immediately unless you supply a positive duration. fade_out_all uses the app’s fade behavior when no duration is supplied. Both accept optional duration_seconds or duration_ms; send one unit at a time. Custom global durations apply to sound players; visual players use the app’s visual fade behavior.

{ "type": "pause_all", "fade": false }
{ "type": "resume_all", "fade": false }

Pause unlocked sound and visual players, or resume paused players. The optional fade flag applies to sound players; visual players use their normal pause and resume behavior.

Use players[].id for every player_id below. A playable ID cannot replace a player ID. Resolve the player again after playback ends or the project changes.

{ "type": "toggle_player_playback", "player_id": "player-id", "fade": false }

Toggle pause/resume. fade is optional.

{ "type": "toggle_player_loop", "player_id": "player-id" }

Toggle the running player’s loop state. Locked players ignore this action. Read the resulting loop_enabled from the player snapshot. This does not edit the project’s playable configuration.

{ "type": "stop_player", "player_id": "player-id" }
{ "type": "fade_out_player", "player_id": "player-id", "duration_seconds": 2 }

Both accept optional duration_seconds or duration_ms. stop_player with a positive duration fades out instead of stopping immediately. fade_out_player uses the default fade when no duration is given.

{ "type": "seek_player", "player_id": "player-id", "position_seconds": 12.5 }

Alternatively send position_percent from 0 to 100. Send one position field at a time. Percentages refer to the full source timeline, even when the playable has trimmed start and stop points. The result is clamped to the player’s playback window. Unknown durations cannot be sought unless an explicit stop time provides a finite timeline. See player state.

{ "type": "set_player_volume", "player_id": "player-id", "volume": 65 }

volume is a display percentage from 0 to 100, not a linear audio gain. Read volume_percent from snapshots for the displayed result.

{ "type": "set_player_muted", "player_id": "player-id", "muted": true, "duration_ms": 1000 }

Use muted: false to unmute. Omit duration_ms or use 0 for an immediate change; a positive duration fades the mute/unmute. The maximum is 60000 ms.

{ "type": "set_next_sound_volume", "volume": 70 }

Set the default volume for future launches to an integer from 0 to 100. This updates control.next_sound_volume.

{ "type": "set_selected_category", "category_id": "category-id" }

Update the shared category selection. Use category_id: null to clear it.

set_volume_level_active and toggle_volume_level

Section titled “set_volume_level_active and toggle_volume_level”
{ "type": "set_volume_level_active", "level_id": "speech", "active": true }
{ "type": "toggle_volume_level", "level_id": "speech" }

Get level_id from control.volume_level_presets[].id. For a hold button, send active: true on press and active: false on release over the same connection. Use toggle_volume_level for a latching button.

The hold belongs to your connection and is released when it disconnects. Sound Show applies the preset’s direction and fade rules to its selected output. control_snapshot reports the new active target immediately; output volume snapshots show the fade progressing.

{ "type": "clear_volume_levels" }

Release all remote-controlled volume levels. This is a global clear, not just the hold belonging to your connection. To release your own hold, send set_volume_level_active with active: false instead.

{ "type": "set_low_volume_active", "active": true }

Activate the low preset, or the first configured preset if low does not exist. New integrations should use an explicit level_id.

Use logical_devices[].id to target a Sound Show logical output. IDs refer to the app’s routing, not operating-system device names or numeric positions.

{ "type": "select_logical_device", "logical_device_id": "main" }
{ "type": "set_logical_device_volume", "logical_device_id": "main", "volume": 80 }

volume is an integer display percentage from 0 to 100. Check the target’s available flag before offering controls.

Discover supported controls and their ranges through capabilities.audio_controls. Only offer a control if its descriptor supports your target’s scope.

{
"type": "set_audio_control",
"target": { "kind": "logical_device", "id": "main" },
"control_id": "five_eq.high_mid_gain_db",
"value": -6,
"fade_duration_ms": 750,
"command_id": "eq-change-1"
}

Required fields are target, control_id, and value. target.kind is logical_device or player, and target.id is that target’s current ID. Values are absolute, in the descriptor’s native units. The server validates the range and the affected effect settings together; a value inside one control’s range can still conflict with another setting, such as EQ crossovers.

{
"type": "reset_audio_control",
"target": { "kind": "player", "id": "player-id" },
"control_id": "pan",
"fade_duration_ms": 500,
"command_id": "pan-reset-1"
}

Reset to the descriptor’s current default_value.

Both commands accept optional fade_duration_ms from 0 to 60000; omitted or 0 applies immediately. A newer command for the same target and control replaces an active fade. Locked players are rejected. Optional command_id is echoed in errors for these commands; it does not create a success response or make retries safe to repeat automatically.

{
"type": "set_project_light_level",
"project_light_id": "project-light-id",
"value_percent": 72,
"fade_duration_ms": 1200,
"command_id": "light-change-1"
}

Use an ID from lights.lights[].id. value_percent is an absolute 0–100 level. fade_duration_ms and command_id are optional with the same bounds and error-correlation behavior as audio controls. A new write to the same light replaces its active fade.

Configure the project light and its QLC+ connection in Sound Show first. The target must be available; starting a fade also requires a readable current level. The command respects the light’s configured range, inversion, and feature access.

{ "type": "trigger_current_instruction_go", "next_volume": 70, "next_pan": 0 }

Trigger GO on the current instruction player. Optional next_volume and next_pan have the same units and defaults as play_playable.

{ "type": "set_instruction_next", "player_index": 0, "path": [1, 0] }

Both fields are required. player_index is a zero-based position in instructions.players. Copy path from the desired item’s snapshot; offer selection for items with can_set_next: true and a nonempty path. This changes the next instruction without triggering GO or editing the definition.

Playlist and item indexes are zero-based positions in the current playlists.playlists array and a playlist’s queue. Resolve them again after state changes; a saved index can point to a different item after reordering.

{ "type": "playlist_play_next", "playlist_index": 0, "activate_autoplay": true, "crossfade_all": false }

All three fields are optional. Omitted playlist_index uses playlists.current_index; activate_autoplay and crossfade_all default to false.

{ "type": "playlist_play_item", "playlist_index": 0, "item_index": 2, "crossfade_all": false }

Both indexes are required. Play the item now using the app’s normal autoplay, looping, and queue-advancement rules. Optional crossfade_all: true requests the app’s right-click behavior; it defaults to false.

{ "type": "set_playlist_autoplay", "playlist_index": 0, "autoplay": true, "crossfade_current_sounds": false }

autoplay is required. Omitted playlist_index uses playlists.current_index. Optional crossfade_current_sounds defaults to false.

Each command requires a zero-based timer_index from the current timers array.

{ "type": "start_timer", "timer_index": 0 }
{ "type": "pause_timer", "timer_index": 0 }
{ "type": "reset_timer", "timer_index": 0 }

These use the timer’s configuration in Sound Show. Read timers_snapshot messages to display elapsed time, remaining time, and running state.