Estado y eventos
Sound Show envía el estado actual del espectáculo tras autenticar y siempre que cambia. Construye el controlador a partir de estas instantáneas y usa la referencia de comandos para solicitar cambios.
Estado completo
Sección «Estado completo»Un mensaje state sustituye todo el estado local. Se recibe automáticamente tras hello_ok, tras cambios generales o de proyecto y en respuesta a request_state. Este ejemplo reducido muestra los campos principales; los proyectos reales tienen arrays poblados y más metadatos.
{ "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": [] } }}Gestiona proyectos ausentes o null, arrays vacíos, campos opcionales y nuevos campos desconocidos. Estas páginas describen la implementación v2 actual. Una versión antigua de Sound Show 2 puede exponer menos campos, comandos o funciones; comprueba hello_ok.features y las capacidades antes de usar funciones opcionales.
Instantáneas de dominio en directo
Sección «Instantáneas de dominio en directo»Tras el estado completo, la mayoría de actualizaciones sustituyen solo un dominio, una parte del estado con nombre. Un array vacío tiene significado: por ejemplo, players: [] borra los reproductores actuales. No combines sus entradas con la lista anterior.
type del mensaje |
Campo local que sustituye | Envío |
|---|---|---|
control_snapshot |
control |
Respuestas directas a comandos de nivel; actualizaciones de controles de todos los operadores con runtime_snapshots. |
players_snapshot |
players |
Cambios de reproductores. |
instructions_snapshot |
instructions |
Con runtime_snapshots. |
playlists_snapshot |
playlists |
Con runtime_snapshots. |
playable_runtime_snapshot |
playable_runtime |
Con runtime_snapshots. |
logical_devices_snapshot |
logical_devices |
Cambios de salidas. |
timers_snapshot |
timers |
Cambios de temporizadores. |
audio_controls_snapshot |
audio_controls |
Cambios de efectos; comparar revision. |
lights_snapshot |
lights |
Cambios de luces; comparar revision. |
Cada mensaje de dominio tiene el campo de datos del mismo nombre y server_time_ms. Por ejemplo:
{ "type": "players_snapshot", "players": [], "server_time_ms": 1712345678901}Los mensajes de controles de audio y luces también incluyen una revisión del dominio:
{ "type": "audio_controls_snapshot", "revision": 5, "audio_controls": { "revision": 5, "logical_devices": [], "players": [] }, "server_time_ms": 1712345678901}Para estos dos dominios, ignora mensajes con revisión inferior a la ya aplicada a ese dominio. No compares revisiones entre dominios. Un state completo restablece la referencia; borra todo el estado local y el seguimiento de revisiones al desconectar. Aplica los otros dominios en orden de recepción.
Solicita runtime_snapshots en hello.features. Sin esta función, los cambios de controles, instrucciones y listas usan estados completos agrupados, salvo respuestas directas a controles. Los cambios solo de actividad de elementos no generan estados completos para clientes sin esta función.
Los cambios en ejecución se agrupan en ciclos de 50 ms. No garantiza un mensaje cada 50 ms ni un registro de todos los cambios intermedios. Un estado completo puede sustituir actualizaciones de dominio pendientes. Consulta el reductor de todos los tipos actuales de instantánea en el ejemplo JavaScript.
Elegir el objetivo correcto
Sección «Elegir el objetivo correcto»| Para… | Usa… |
|---|---|
| Iniciar un botón del proyecto | project.categories[].playables[].id como playable_id. |
| Seleccionar una categoría | project.categories[].id como category_id. |
| Detener, pausar, desplazar o ajustar una instancia en ejecución | players[].id como player_id. |
| Controlar una salida | logical_devices[].id como logical_device_id. |
| Activar un preajuste de volumen | control.volume_level_presets[].id como level_id. |
| Ajustar un efecto | id del descriptor como control_id, más un objetivo actual de reproductor o dispositivo lógico. |
| Ajustar una luz | lights.lights[].id como project_light_id. |
| Reproducir un elemento de lista | Posiciones actuales de lista y cola desde cero. |
| Seleccionar una instrucción | Posición actual del reproductor de instrucciones desde cero y path del elemento. |
| Controlar un temporizador | Su posición actual desde cero como timer_index. |
Los ID de reproductor describen instancias en ejecución y no deben guardarse como identidad permanente del proyecto. Un elemento puede tener varios reproductores activos. Busca source_playable_id o state_playable_id correspondientes en la instantánea actual y elige explícitamente la instancia deseada. Los nombres sirven para mostrar, pero no tienen por qué ser únicos.
Proyecto y elementos reproducibles
Sección «Proyecto y elementos reproducibles»project.categories[] contiene, para categorías, id, name, color, is_hidden, el icon_url opcional y playables. Un elemento incluye:
{ "id": "playable-id", "name": "Wind", "kind": "sound", "color": "#3b82f6", "tags": [], "is_searchable": true, "runtime_state_key": "playable-id", "target_category_id": null}Los tipos comunes son sound, video, image, random, timer, playlist, action, webbrowser, category_link y instruction. Tolera tipos nuevos o unsupported. Los metadatos opcionales incluyen icon_url, atajos de teclado e ID configurados de acciones de clic.
playable_runtime contiene entradas con state_playable_id, play_count, is_locked y is_playing. Relaciona el runtime_state_key del elemento, o su id si falta aquel, con state_playable_id. Los elementos vinculados pueden compartir actividad y bloqueo. Este bloqueo del botón del proyecto es distinto del bloqueo de control de un reproductor en ejecución.
Las categorías pueden incluir grid_layout opcional con enabled, columns, rows, pages, positions y revision. Comprueba capabilities.manual_grid_layout antes de seguirlo. Los clientes pueden ignorar estos metadatos y mostrar la lista normal; no existe un comando remoto para editar la distribución.
Reproductores
Sección «Reproductores»{ "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"}Usa volume_percent directamente para mostrar. El campo bruto separado volume, si existe, no es un porcentaje que multiplicar por 100; la aplicación puede usar una escala de volumen no lineal.
Los campos de la línea temporal están en segundos. start_time_seconds, stop_time_seconds y timeline_duration_seconds pueden faltar o ser null. Úsalos para relacionar la ventana recortada con la línea temporal de origen al buscar una posición. Otros campos opcionales: remaining_playback_seconds, markers y icon_url.
Salidas y controles compartidos
Sección «Salidas y controles compartidos»logical_devices[] proporciona id, label, display_label, color, output_role, available, selected y volume_percent. Usa display_label para mostrar y id para comandos.
control expone el volumen del próximo inicio y la categoría seleccionada, más volume_level_presets, active_volume_level_ids y effective_volume_level_id. Los preajustes incluyen id, name, direction (both, up_only o down_only), target_volume_percent, fade_down_ms y fade_up_ms. low_volume_active admite controladores antiguos. Lee los ID activos en la instantánea; otros operadores también pueden cambiarlos.
Listas, instrucciones y temporizadores
Sección «Listas, instrucciones y temporizadores»| Dominio | Campos útiles |
|---|---|
playlists |
current_index y playlists[]. Cada lista tiene id, title, autoplay, loop_enabled y queue. Los elementos de cola incluyen playable_id, title y icon_url opcional. Los metadatos de ejecución pueden incluir active_item_id, active_item_title y active_player_id. |
instructions |
current_index y players[]. Los reproductores tienen id, title, has_instruction, waiting_for_go, next_instruction_text y items. Los elementos exponen item_id, title, kind, depth, path, can_set_next, is_next_to_play y is_visibly_playing. |
timers |
Array con id numérico, mode, is_running, is_locked, elapsed_ms, duration_ms, remaining_ms y is_over_time. Los tiempos usan milisegundos. |
Para previsualizar GO, prefiere el siguiente elemento más profundo con path no vacío y kind distinto de group; en su defecto, cualquiera de los siguientes más profundos. Para seleccionar el siguiente, usa su path real, no una ruta deducida del título o la profundidad.
Controles de audio y capacidades
Sección «Controles de audio y capacidades»capabilities.audio_controls[] describe los controles de efectos disponibles. Cada descriptor proporciona:
| Campo | Significado |
|---|---|
id, label |
Identificador del protocolo y etiqueta visible. |
scopes |
Tipos de objetivo admitidos: logical_device y/o player. |
min, max, default_value |
Límites numéricos nativos y valor de restablecimiento. |
suggested_step |
Paso de ajuste sugerido. |
unit, scale |
Unidad visible y escala. log2 expresa pasos en octavas. |
display_multiplier |
Multiplicar valores nativos para mostrar; dividir la entrada del usuario por este factor antes de enviar. |
Por ejemplo, una proporción de 0.5 con display_multiplier: 100 se muestra como 50%. Usa el catálogo anunciado en vez de fijar rangos en el código.
audio_controls contiene revision, logical_devices[] y players[]. Cada objetivo tiene kind, id, label, available, locked y un objeto values que relaciona ID de controles con valores numéricos nativos. Los controles lineales aplican fundidos lineales; los log2, geométricos.
Luces
Sección «Luces»lights contiene revision y lights[]. Cada luz tiene id, name, capability (actualmente level) y available. Su value_percent se omite cuando el adaptador no está disponible. Muéstralo como no disponible, no como cero.
Iconos
Sección «Iconos»Las entradas pueden incluir una icon_url relativa y opaca, por ejemplo /asset/file?id=opaque-asset-id. Resuélvela respecto a la dirección HTTP del servidor remoto y obténla por HTTP. Los iconos no son mensajes WebSocket.
Usa la URL proporcionada sin construir ID ni enviar rutas de archivos. Guarda los iconos en caché para la sesión actual del servidor y espera nuevos ID tras reiniciar. Los cambios de proyecto pueden dejar recursos no disponibles; ofrece una alternativa si falla una imagen. Las instantáneas no exponen rutas del sistema de archivos local.
Errores y límites
Sección «Errores y límites»Una conexión autenticada puede recibir:
{ "type": "error", "code": "invalid_value", "command_id": "eq-change-1", "message": "Human-readable error description"}code y command_id son opcionales. Los errores de audio/luces pueden incluir unknown_control, target_locked, target_not_found, invalid_value, target_unavailable o command_failed. Los comandos antiguos pueden devolver solo message. No interpretes el texto legible como un código estable. Un error puede dejar la conexión abierta; sigue procesando instantáneas.
| Límite | Comportamiento del cliente |
|---|---|
| Primer mensaje en 10 segundos | Enviar hello al abrir. |
| 16 conexiones WebSocket simultáneas | Reutilizar conexiones y cerrar clientes sin uso. Incluye sockets no autenticados. |
| 64 KiB por mensaje/trama entrante | Un pequeño comando JSON por mensaje. |
| Ráfaga de 60 comandos, repuesta a 20 por segundo por conexión | Limitar deslizadores y agrupar valores pendientes. Ping y actualización también consumen esta cuota. |
| Cinco contraseñas incorrectas desde una dirección en 60 segundos | Corregir y esperar; nuevas aperturas WebSocket se bloquean durante 60 segundos con HTTP 429 y Retry-After. |
Un comando rechazado por el límite de frecuencia no se aplica y devuelve code: "rate_limited". Un exceso continuado puede cerrar la conexión. Respeta Retry-After cuando el cliente exponga la respuesta HTTP. Si un navegador solo indica un fallo tras errores de autenticación repetidos, espera al menos 60 segundos. No repitas a ciegas reproducción, alternancia o GO: puedes activar una segunda acción.
Señal de actividad y reconexión
Sección «Señal de actividad y reconexión»Si hello_ok.features incluye ping, un cliente autenticado puede enviar {"type":"ping"} y esperar {"type":"pong"}. El control remoto integrado envía un ping cada diez segundos y, en esa comprobación, reconecta si lleva más de 25 segundos sin recibir un mensaje válido. Los dominios sin cambios pueden permanecer en silencio.
Para un controlador persistente:
- Desactiva el envío cuando se cierre el socket o falle la señal de actividad.
- Borra el estado en caché, ID de reproductores y seguimiento de revisiones.
- Reconecta con una espera limitada que aumente tras fallos repetidos. Respeta los errores de autenticación y límites de frecuencia en vez de reintentar continuamente.
- Envía un nuevo
hello, espera el nuevostatecompleto y vuelve a identificar objetivos. - Reactiva los controles con ese estado. No repitas inicios, alternancias o GO pendientes tras reconectar.
Las pulsaciones de volumen asociadas a la conexión se liberan al desconectar. Trata la reconexión como una nueva sesión, aunque no cambie la dirección del servidor.
Cambiar Permitir orígenes externos en Sound Show tiene efecto inmediato y desconecta a los clientes actuales. Tras desactivarlo, navegadores de otros orígenes no pueden reconectar. Consulta los controles web personalizados para conocer la configuración y las restricciones del navegador.