Zustand und Ereignisse
Sound Show sendet nach der Authentifizierung und bei Änderungen den aktuellen Show-Zustand. Bauen Sie Ihren Controller aus diesen Snapshots auf und fordern Sie Änderungen mit der Befehlsreferenz an.
Vollständiger Zustand
Abschnitt „Vollständiger Zustand“Eine state-Nachricht ersetzt den gesamten lokalen Zustand. Sie kommt automatisch nach hello_ok, nach umfassenden oder Projektänderungen und als Antwort auf request_state. Dieses gekürzte Beispiel zeigt die Hauptfelder; echte Projekte enthalten gefüllte Arrays und weitere Metadaten.
{ "type": "state", "protocol_version": 2, "server_time_ms": 1712345678901, "state": { "project": { "name": "My show", "categories": [] }, "players": [], "playable_runtime": [], "playlists": { "current_index": 0, "playlists": [] }, "instructions": { "current_index": 0, "players": [] }, "timers": [], "logical_devices": [], "control": { "next_sound_volume": 70, "selected_category_id": null, "low_volume_active": false, "volume_level_presets": [], "active_volume_level_ids": [], "effective_volume_level_id": null }, "capabilities": { "audio_controls": [], "manual_grid_layout": false }, "audio_controls": { "revision": 1, "logical_devices": [], "players": [] }, "lights": { "revision": 1, "lights": [] } }}Berücksichtigen Sie fehlende oder null-Projekte, leere Arrays, optionale sowie unbekannte zusätzliche Felder. Diese Dokumentation beschreibt die aktuelle v2-Implementierung. Ältere Sound Show 2-Versionen bieten möglicherweise weniger Felder, Befehle oder Funktionen; prüfen Sie hello_ok.features und die Fähigkeiten im Zustand vor optionalen Funktionen.
Laufende Domain-Snapshots
Abschnitt „Laufende Domain-Snapshots“Nach dem vollständigen Zustand ersetzen die meisten Laufzeit-Updates nur eine Domain, einen benannten Zustandsteil. Ein leeres Array ist bedeutend: players: [] entfernt beispielsweise alle aktuellen Player. Führen Sie Array-Einträge nicht mit der alten Liste zusammen.
Nachrichten-type |
Zu ersetzendes lokales Feld | Übermittlung |
|---|---|---|
control_snapshot |
control |
Direkte Antworten auf Lautstärkepegel-Befehle; Steuerungsänderungen aller Bediener mit runtime_snapshots. |
players_snapshot |
players |
Player-Änderungen. |
instructions_snapshot |
instructions |
Mit runtime_snapshots. |
playlists_snapshot |
playlists |
Mit runtime_snapshots. |
playable_runtime_snapshot |
playable_runtime |
Mit runtime_snapshots. |
logical_devices_snapshot |
logical_devices |
Ausgangsänderungen. |
timers_snapshot |
timers |
Timer-Änderungen. |
audio_controls_snapshot |
audio_controls |
Effektänderungen; revision vergleichen. |
lights_snapshot |
lights |
Lichtänderungen; revision vergleichen. |
Jede Domain-Nachricht enthält das gleichnamige Datenfeld und server_time_ms. Beispiel:
{ "type": "players_snapshot", "players": [], "server_time_ms": 1712345678901}Nachrichten für Audioregler und Licht enthalten außerdem eine Domain-Revision:
{ "type": "audio_controls_snapshot", "revision": 5, "audio_controls": { "revision": 5, "logical_devices": [], "players": [] }, "server_time_ms": 1712345678901}Ignorieren Sie in diesen beiden Domains Nachrichten mit einer niedrigeren Revision als der bereits angewendeten. Vergleichen Sie keine Revisionen verschiedener Domains. Ein vollständiger state setzt die Basis zurück; löschen Sie bei Trennung den gesamten lokalen Zustand und die Revisionsverfolgung. Andere Domains werden in Empfangsreihenfolge angewendet.
Fordern Sie runtime_snapshots in hello.features an. Ohne diese Funktion kommen Steuerungs-, Anweisungs- und Playlist-Änderungen als zusammengefasste vollständige Zustände, außer direkten Steuerungsantworten. Reine Aktivitätsänderungen von Spielelementen lösen für Clients ohne diese Funktion keine vollständigen Zustände aus.
Laufzeitänderungen werden im 50-ms-Zyklus zusammengefasst. Das garantiert weder eine Nachricht alle 50 ms noch ein Ereignisprotokoll jeder Zwischenänderung. Ein vollständiger Zustand kann ausstehende Domain-Updates ersetzen. Der Reducer im JavaScript-Beispiel verarbeitet alle aktuellen Snapshot-Typen.
Das richtige Ziel wählen
Abschnitt „Das richtige Ziel wählen“| Gewünschte Aktion | Verwenden |
|---|---|
| Projektschaltfläche starten | project.categories[].playables[].id als playable_id. |
| Kategorie wählen | project.categories[].id als category_id. |
| Eine laufende Instanz stoppen, pausieren, verschieben oder regeln | players[].id als player_id. |
| Ausgang steuern | logical_devices[].id als logical_device_id. |
| Lautstärke-Preset aktivieren | control.volume_level_presets[].id als level_id. |
| Effekt regeln | id des Deskriptors als control_id und ein aktuelles Player- oder logisches Geräte-Ziel. |
| Lichtpegel einstellen | lights.lights[].id als project_light_id. |
| Playlist-Element abspielen | Aktuelle Playlist- und Warteschlangenpositionen ab null. |
| Anweisung wählen | Aktuelle Position des Anweisungsplayers ab null und path des Elements. |
| Timer steuern | Seine aktuelle Position ab null als timer_index. |
Player-IDs bezeichnen laufende Instanzen und dürfen nicht als dauerhafte Projektidentität gespeichert werden. Ein Spielelement kann mehrere aktive Player haben. Suchen Sie passende source_playable_id oder state_playable_id im aktuellen Player-Snapshot und wählen Sie ausdrücklich die gewünschte Instanz. Namen eignen sich zur Anzeige, sind aber nicht unbedingt eindeutig.
Projekt und Spielelemente
Abschnitt „Projekt und Spielelemente“project.categories[] enthält für Kategorien id, name, color, is_hidden, optional icon_url und playables. Ein Spielelement umfasst:
{ "id": "playable-id", "name": "Wind", "kind": "sound", "color": "#3b82f6", "tags": [], "is_searchable": true, "runtime_state_key": "playable-id", "target_category_id": null}Häufige Typen sind sound, video, image, random, timer, playlist, action, webbrowser, category_link und instruction. Akzeptieren Sie neue oder unsupported-Typen. Optionale Metadaten umfassen icon_url, Tastenkürzel und konfigurierte Klickaktions-IDs.
playable_runtime enthält Einträge mit state_playable_id, play_count, is_locked und is_playing. Ordnen Sie runtime_state_key eines Spielelements, ersatzweise dessen id, dem Feld state_playable_id zu. Verknüpfte Spielelemente können Aktivität und Sperrzustand teilen. Diese Projektschaltflächen-Sperre unterscheidet sich von der Steuerungssperre eines laufenden Players.
Kategorien können optional grid_layout mit enabled, columns, rows, pages, positions und revision enthalten. Prüfen Sie vor Verwendung capabilities.manual_grid_layout. Clients können diese Metadaten ignorieren und die normale Liste anzeigen; es gibt keinen Remote-Befehl zum Bearbeiten des Layouts.
Player
Abschnitt „Player“{ "id": "runtime-player-id", "kind": "sound", "title": "Wind", "color": "#3b82f6", "panel_position": 0, "position_seconds": 12.3, "duration_seconds": 95, "start_time_seconds": 5, "stop_time_seconds": 90, "timeline_duration_seconds": 95, "volume_percent": 70, "muted": false, "is_playing": true, "is_locked": false, "loop_enabled": true, "output_logical_device_id": "main", "source_playable_id": "playable-id", "state_playable_id": "playable-id"}Verwenden Sie volume_percent direkt zur Anzeige. Das separate Rohfeld volume, falls vorhanden, ist kein mit 100 zu multiplizierender Prozentwert; die App kann eine nichtlineare Lautstärkeskala verwenden.
Zeitachsenfelder sind in Sekunden. start_time_seconds, stop_time_seconds und timeline_duration_seconds können fehlen oder null sein. Damit lässt sich beim Springen ein zugeschnittenes Wiedergabefenster auf die Quellzeitachse abbilden. Weitere optionale Felder: remaining_playback_seconds, markers und icon_url.
Ausgänge und gemeinsame Steuerung
Abschnitt „Ausgänge und gemeinsame Steuerung“logical_devices[] bietet id, label, display_label, color, output_role, available, selected und volume_percent. Verwenden Sie display_label zur Anzeige und id für Befehle.
control enthält Lautstärke des nächsten Starts und gewählte Kategorie sowie volume_level_presets, active_volume_level_ids und effective_volume_level_id. Presets enthalten id, name, direction (both, up_only oder down_only), target_volume_percent, fade_down_ms und fade_up_ms. low_volume_active unterstützt ältere Controller. Lesen Sie aktive IDs aus dem Snapshot; andere Bediener können sie ebenfalls ändern.
Playlists, Anweisungen und Timer
Abschnitt „Playlists, Anweisungen und Timer“| Domain | Nützliche Felder |
|---|---|
playlists |
current_index und playlists[]. Jede Playlist hat id, title, autoplay, loop_enabled und queue. Warteschlangenelemente enthalten playable_id, title und optional icon_url. Laufzeitmetadaten können active_item_id, active_item_title und active_player_id enthalten. |
instructions |
current_index und players[]. Player haben id, title, has_instruction, waiting_for_go, next_instruction_text und items. Elemente bieten item_id, title, kind, depth, path, can_set_next, is_next_to_play und is_visibly_playing. |
timers |
Array mit numerischem id, mode, is_running, is_locked, elapsed_ms, duration_ms, remaining_ms und is_over_time. Timer-Zeiten sind in Millisekunden. |
Bevorzugen Sie für die GO-Vorschau das tiefste nächste Element mit nicht leerem path und einem anderen kind als group; andernfalls ein beliebiges tiefstes nächstes Element. Verwenden Sie zur Auswahl dessen echten path, keinen aus Titel oder Tiefe abgeleiteten Pfad.
Audioregler und Fähigkeiten
Abschnitt „Audioregler und Fähigkeiten“capabilities.audio_controls[] beschreibt verfügbare Effektregler. Jeder Deskriptor liefert:
| Feld | Bedeutung |
|---|---|
id, label |
Protokollkennung und Anzeigename. |
scopes |
Unterstützte Zieltypen: logical_device und/oder player. |
min, max, default_value |
Native numerische Grenzen und Rücksetzwert. |
suggested_step |
Vorgeschlagene Schrittweite. |
unit, scale |
Anzeigeeinheit und Reglerskala. log2 beschreibt Schritte in Oktaven. |
display_multiplier |
Native Werte zur Anzeige multiplizieren; Benutzereingaben vor dem Senden dadurch teilen. |
Ein Verhältnis von 0.5 mit display_multiplier: 100 erscheint beispielsweise als 50%. Verwenden Sie den angekündigten Katalog, statt Bereiche fest einzuprogrammieren.
audio_controls enthält revision, logical_devices[] und players[]. Jedes Ziel hat kind, id, label, available, locked und ein values-Objekt, das Regler-IDs nativen Zahlenwerten zuordnet. Lineare Regler blenden linear, log2-Regler geometrisch.
Lichter
Abschnitt „Lichter“lights enthält revision und lights[]. Jedes Licht hat id, name, capability (derzeit level) und available. Bei nicht verfügbarem Adapter fehlt value_percent. Zeigen Sie dies als nicht verfügbar, nicht als null an.
Symbole
Abschnitt „Symbole“Snapshot-Einträge können eine undurchsichtige relative icon_url enthalten, etwa /asset/file?id=opaque-asset-id. Lösen Sie sie gegen die HTTP-Adresse des Remote-Servers auf und laden Sie sie per HTTP. Symbole sind keine WebSocket-Nachrichten.
Verwenden Sie die bereitgestellte URL, ohne IDs zu konstruieren oder Dateipfade zu senden. Cachen Sie Symbole für die aktuelle Serversitzung; nach einem Neustart sind neue IDs möglich. Projektänderungen können Ressourcen unverfügbar machen; bieten Sie bei fehlgeschlagenen Bildanfragen einen Ersatz. Lokale Dateisystempfade erscheinen nicht in Snapshots.
Fehler und Grenzen
Abschnitt „Fehler und Grenzen“Eine authentifizierte Verbindung kann Folgendes empfangen:
{ "type": "error", "code": "invalid_value", "command_id": "eq-change-1", "message": "Human-readable error description"}code und command_id sind optional. Audio-/Lichtfehler können unknown_control, target_locked, target_not_found, invalid_value, target_unavailable oder command_failed enthalten. Ältere Befehlspfade liefern eventuell nur message. Behandeln Sie lesbaren Text nicht als stabilen Fehlercode. Nach einem Fehler kann die Verbindung offen bleiben; verarbeiten Sie weiter Snapshots.
| Grenze | Client-Verhalten |
|---|---|
| Erste Nachricht innerhalb von 10 Sekunden | hello sofort beim Öffnen senden. |
| 16 gleichzeitige WebSocket-Verbindungen | Verbindungen wiederverwenden und ungenutzte Clients schließen. Nicht authentifizierte Sockets zählen mit. |
| 64 KiB pro eingehender Nachricht/Frame | Pro Nachricht einen kleinen JSON-Befehl senden. |
| Burst von 60 Befehlen, aufgefüllt mit 20 pro Sekunde je Verbindung | Schieberegler drosseln und ausstehende Werte zusammenfassen. Ping und Aktualisierungen verbrauchen dieses Budget ebenfalls. |
| Fünf falsche Passwörter von einer Quelladresse in 60 Sekunden | Passwort korrigieren und warten; neue Upgrades sind für 60 Sekunden blockiert und liefern HTTP 429 mit Retry-After. |
Ein wegen Ratenbegrenzung abgelehnter Befehl wird nicht angewendet und liefert code: "rate_limited". Dauerhafte Überschreitung kann die Verbindung schließen. Beachten Sie Retry-After, wenn Ihr Client die HTTP-Antwort bereitstellt. Meldet ein Browser nach wiederholten Authentifizierungsfehlern nur einen Verbindungsfehler, warten Sie mindestens 60 Sekunden. Wiederholen Sie Wiedergabe-, Umschalt- oder GO-Befehle nicht blind: Das kann eine zweite Aktion auslösen.
Heartbeat und Wiederverbindung
Abschnitt „Heartbeat und Wiederverbindung“Enthält hello_ok.features den Eintrag ping, kann ein authentifizierter Client {"type":"ping"} senden und {"type":"pong"} erwarten. Die integrierte Fernbedienung sendet alle zehn Sekunden einen Ping und verbindet sich bei dieser Prüfung neu, wenn über 25 Sekunden keine gültige Nachricht ankam. Unveränderte Domains können ansonsten still bleiben.
Für einen dauerhaft verbundenen Controller:
- Befehlsversand bei geschlossenem Socket oder fehlgeschlagenem Heartbeat sofort deaktivieren.
- Zustandscache, Player-IDs und Revisionsverfolgung löschen.
- Mit begrenzter, bei wiederholten Fehlern wachsender Verzögerung neu verbinden. Authentifizierungsfehler und Ratenbegrenzungen beachten, statt ständig neu zu versuchen.
- Ein neues
hellosenden, auf den neuen vollständigenstatewarten und Ziele neu ermitteln. - Steuerung anhand dieses Zustands reaktivieren. Aufgestaute Start-, Umschalt- oder GO-Befehle nach Wiederverbindung nicht erneut abspielen.
Verbindungsgebundene Lautstärke-Halteaktionen enden beim Trennen. Behandeln Sie die Wiederverbindung als neue Sitzung, auch bei unveränderter Serveradresse.
Änderungen an Externe Origins erlauben in Sound Show gelten sofort und trennen aktuelle Clients. Nach dem Deaktivieren können Browser anderer Origins sich nicht erneut verbinden. Siehe eigene Browser-Fernbedienungen für Konfiguration und Browserbeschränkungen.