Zum Inhalt springen
Dokumentation
Herunterladen
Deutsch

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.

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.

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.

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.

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.

{
"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.

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.

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.

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.

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.

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:

  1. Befehlsversand bei geschlossenem Socket oder fehlgeschlagenem Heartbeat sofort deaktivieren.
  2. Zustandscache, Player-IDs und Revisionsverfolgung löschen.
  3. Mit begrenzter, bei wiederholten Fehlern wachsender Verzögerung neu verbinden. Authentifizierungsfehler und Ratenbegrenzungen beachten, statt ständig neu zu versuchen.
  4. Ein neues hello senden, auf den neuen vollständigen state warten und Ziele neu ermitteln.
  5. 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.