Estado e eventos
O Sound Show envia o estado atual do espetáculo após a autenticação e sempre que muda. Construa o controlador com estes instantâneos e use a referência de comandos para pedir alterações.
Estado completo
Secção «Estado completo»Uma mensagem state substitui todo o estado local. Recebe-a automaticamente após hello_ok, após alterações gerais ou de projeto e em resposta a request_state. Este exemplo reduzido mostra os campos principais; projetos reais têm arrays preenchidos e mais metadados.
{ "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": [] } }}Trate projetos ausentes ou null, arrays vazios, campos opcionais e novos campos desconhecidos. Estas páginas descrevem a implementação v2 atual. Uma versão antiga do Sound Show 2 pode ter menos campos, comandos ou funções; verifique hello_ok.features e as capacidades do estado antes de usar funções opcionais.
Instantâneos de domínio em direto
Secção «Instantâneos de domínio em direto»Após o estado completo, a maioria das atualizações substitui apenas um domínio, uma parte nomeada do estado. Um array vazio tem significado: por exemplo, players: [] limpa os leitores atuais. Não junte as entradas à lista antiga.
type da mensagem |
Campo local a substituir | Envio |
|---|---|---|
control_snapshot |
control |
Respostas diretas a comandos de nível de volume; atualizações dos controlos de todos os operadores com runtime_snapshots. |
players_snapshot |
players |
Alterações dos leitores. |
instructions_snapshot |
instructions |
Com runtime_snapshots. |
playlists_snapshot |
playlists |
Com runtime_snapshots. |
playable_runtime_snapshot |
playable_runtime |
Com runtime_snapshots. |
logical_devices_snapshot |
logical_devices |
Alterações das saídas. |
timers_snapshot |
timers |
Alterações dos temporizadores. |
audio_controls_snapshot |
audio_controls |
Alterações dos efeitos; comparar revision. |
lights_snapshot |
lights |
Alterações das luzes; comparar revision. |
Cada mensagem de domínio tem o campo de dados com o nome correspondente e server_time_ms. Por exemplo:
{ "type": "players_snapshot", "players": [], "server_time_ms": 1712345678901}As mensagens de controlos de áudio e luzes também incluem uma revisão de domínio:
{ "type": "audio_controls_snapshot", "revision": 5, "audio_controls": { "revision": 5, "logical_devices": [], "players": [] }, "server_time_ms": 1712345678901}Nestes dois domínios, ignore mensagens com revisão inferior à já aplicada a esse domínio. Não compare revisões entre domínios. Um state completo repõe a referência; limpe todo o estado local e as revisões ao desligar. Aplique os outros domínios pela ordem de receção.
Peça runtime_snapshots em hello.features. Sem esta função, as alterações de controlos, instruções e listas usam estados completos agrupados, exceto respostas diretas aos controlos. Alterações apenas de atividade dos elementos não geram estados completos para clientes sem esta função.
As alterações de execução são agrupadas num ciclo de 50 ms. Isto não garante uma mensagem a cada 50 ms nem um registo de todas as alterações intermédias. Um estado completo pode substituir atualizações de domínio pendentes. Veja o redutor que trata todos os tipos atuais de instantâneo no exemplo JavaScript.
Escolher o alvo certo
Secção «Escolher o alvo certo»| Para… | Use… |
|---|---|
| Iniciar um botão do projeto | project.categories[].playables[].id como playable_id. |
| Selecionar uma categoria | project.categories[].id como category_id. |
| Parar, pausar, deslocar ou ajustar uma instância em execução | players[].id como player_id. |
| Controlar uma saída | logical_devices[].id como logical_device_id. |
| Ativar uma predefinição de volume | control.volume_level_presets[].id como level_id. |
| Ajustar um efeito | id do descritor como control_id, mais um alvo atual de leitor ou dispositivo lógico. |
| Definir o nível de uma luz | lights.lights[].id como project_light_id. |
| Reproduzir um elemento de lista | Posições atuais de lista e fila a partir de zero. |
| Selecionar uma instrução | Posição atual do leitor de instruções a partir de zero e path do elemento. |
| Controlar um temporizador | A posição atual a partir de zero como timer_index. |
IDs de leitor identificam instâncias em execução e não devem ser guardados como identidade permanente do projeto. Um elemento pode ter vários leitores ativos. Procure source_playable_id ou state_playable_id correspondentes no instantâneo atual e escolha explicitamente a instância pretendida. Os nomes são úteis para apresentação, mas podem não ser únicos.
Projeto e elementos reproduzíveis
Secção «Projeto e elementos reproduzíveis»project.categories[] contém, para categorias, id, name, color, is_hidden, o icon_url opcional e playables. Um elemento inclui:
{ "id": "playable-id", "name": "Wind", "kind": "sound", "color": "#3b82f6", "tags": [], "is_searchable": true, "runtime_state_key": "playable-id", "target_category_id": null}Os tipos comuns são sound, video, image, random, timer, playlist, action, webbrowser, category_link e instruction. Aceite tipos novos ou unsupported. Os metadados opcionais incluem icon_url, atalhos de teclado e IDs de ações de clique configuradas.
playable_runtime contém entradas com state_playable_id, play_count, is_locked e is_playing. Associe o runtime_state_key do elemento, ou id se aquele faltar, a state_playable_id. Elementos ligados podem partilhar atividade e bloqueio. Este bloqueio do botão do projeto é diferente do bloqueio de controlo de um leitor em execução.
As categorias também podem incluir grid_layout opcional com enabled, columns, rows, pages, positions e revision. Verifique capabilities.manual_grid_layout antes de o seguir. Os clientes podem ignorar estes metadados e apresentar a lista normal; não existe comando remoto para editar a disposição.
Leitores
Secção «Leitores»{ "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"}Use volume_percent diretamente na apresentação. O campo bruto separado volume, quando existe, não é uma percentagem para multiplicar por 100; a aplicação pode usar uma escala de volume não linear.
Os campos da linha temporal estão em segundos. start_time_seconds, stop_time_seconds e timeline_duration_seconds podem faltar ou ser null. Use-os para relacionar a janela recortada com a linha temporal de origem ao procurar uma posição. Outros campos opcionais: remaining_playback_seconds, markers e icon_url.
Saídas e controlos partilhados
Secção «Saídas e controlos partilhados»logical_devices[] fornece id, label, display_label, color, output_role, available, selected e volume_percent. Use display_label na apresentação e id nos comandos.
control expõe o volume do próximo início e a categoria selecionada, além de volume_level_presets, active_volume_level_ids e effective_volume_level_id. As predefinições incluem id, name, direction (both, up_only ou down_only), target_volume_percent, fade_down_ms e fade_up_ms. low_volume_active suporta controladores antigos. Leia os IDs ativos no instantâneo; outros operadores também os podem alterar.
Listas, instruções e temporizadores
Secção «Listas, instruções e temporizadores»| Domínio | Campos úteis |
|---|---|
playlists |
current_index e playlists[]. Cada lista tem id, title, autoplay, loop_enabled e queue. Os elementos da fila incluem playable_id, title e icon_url opcional. Os metadados de execução podem incluir active_item_id, active_item_title e active_player_id. |
instructions |
current_index e players[]. Os leitores têm id, title, has_instruction, waiting_for_go, next_instruction_text e items. Os elementos expõem item_id, title, kind, depth, path, can_set_next, is_next_to_play e is_visibly_playing. |
timers |
Array com id numérico, mode, is_running, is_locked, elapsed_ms, duration_ms, remaining_ms e is_over_time. Os tempos usam milissegundos. |
Na pré-visualização de GO, prefira o próximo elemento mais profundo com path não vazio e kind diferente de group; na falta deste, use qualquer próximo elemento mais profundo. Para selecionar o seguinte, use o path real, não um caminho deduzido do título ou profundidade.
Controlos de áudio e capacidades
Secção «Controlos de áudio e capacidades»capabilities.audio_controls[] descreve os controlos de efeitos disponíveis. Cada descritor fornece:
| Campo | Significado |
|---|---|
id, label |
Identificador do protocolo e rótulo de apresentação. |
scopes |
Tipos de alvo suportados: logical_device e/ou player. |
min, max, default_value |
Limites numéricos nativos e valor de reposição. |
suggested_step |
Passo de ajuste sugerido. |
unit, scale |
Unidade de apresentação e escala. log2 exprime passos em oitavas. |
display_multiplier |
Multiplicar valores nativos para apresentar; dividir a entrada do utilizador por este fator antes de enviar. |
Por exemplo, uma razão 0.5 com display_multiplier: 100 aparece como 50%. Use o catálogo anunciado em vez de fixar intervalos no código.
audio_controls contém revision, logical_devices[] e players[]. Cada alvo tem kind, id, label, available, locked e um objeto values que associa IDs de controlo a valores numéricos nativos. Os controlos lineares fazem transições lineares; os log2, geométricas.
Luzes
Secção «Luzes»lights contém revision e lights[]. Cada luz tem id, name, capability (atualmente level) e available. O value_percent é omitido quando o adaptador está indisponível. Apresente essa indisponibilidade, em vez de a interpretar como zero.
Ícones
Secção «Ícones»As entradas podem incluir um icon_url relativo e opaco, como /asset/file?id=opaque-asset-id. Resolva-o face ao endereço HTTP do servidor remoto e obtenha-o por HTTP. Os ícones não são mensagens WebSocket.
Use a URL fornecida sem construir IDs nem enviar caminhos de ficheiros. Guarde os ícones em cache durante a sessão atual do servidor e espere IDs novos após reiniciar. Alterações de projeto podem tornar recursos indisponíveis; preveja uma alternativa quando o pedido de imagem falhar. Os instantâneos não expõem caminhos do sistema de ficheiros local.
Erros e limites
Secção «Erros e limites»Uma ligação autenticada pode receber:
{ "type": "error", "code": "invalid_value", "command_id": "eq-change-1", "message": "Human-readable error description"}code e command_id são opcionais. Erros de áudio/luzes podem incluir unknown_control, target_locked, target_not_found, invalid_value, target_unavailable ou command_failed. Comandos antigos podem devolver apenas message. Não interprete o texto legível como código de erro estável. Um erro pode manter a ligação aberta; continue a processar instantâneos.
| Limite | Comportamento do cliente |
|---|---|
| Primeira mensagem em 10 segundos | Enviar hello logo ao abrir. |
| 16 ligações WebSocket simultâneas | Reutilizar ligações e fechar clientes sem uso. Inclui sockets não autenticados. |
| 64 KiB por mensagem/trama recebida | Uma pequena mensagem JSON por comando. |
| Rajada de 60 comandos, reposta a 20 por segundo por ligação | Limitar cursores e agrupar valores pendentes. Ping e pedidos de atualização também usam este orçamento. |
| Cinco palavras-passe erradas do mesmo endereço em 60 segundos | Corrigir e esperar; novas aberturas WebSocket ficam bloqueadas durante 60 segundos e devolvem HTTP 429 com Retry-After. |
Um comando rejeitado pelo limite de frequência não é aplicado e devolve code: "rate_limited". Excesso continuado pode fechar a ligação. Respeite Retry-After quando o cliente expõe a resposta HTTP. Se o navegador apenas indicar falha após erros de autenticação repetidos, espere pelo menos 60 segundos. Não repita cegamente comandos de reprodução, alternância ou GO: pode desencadear uma segunda ação.
Sinal de presença e nova ligação
Secção «Sinal de presença e nova ligação»Quando hello_ok.features inclui ping, um cliente autenticado pode enviar {"type":"ping"} e esperar {"type":"pong"}. O comando remoto integrado envia um ping a cada dez segundos e, nessa verificação, volta a ligar-se se não recebeu mensagem válida há mais de 25 segundos. Domínios sem alterações podem permanecer silenciosos.
Para um controlador persistente:
- Desative o envio logo que o socket feche ou falhe o sinal de presença.
- Limpe o estado em cache, IDs de leitores e registo de revisões.
- Volte a ligar com um atraso limitado que aumente após falhas repetidas. Respeite erros de autenticação e limites de frequência em vez de tentar continuamente.
- Envie um novo
hello, aguarde o novostatecompleto e volte a identificar os alvos. - Reative os controlos com esse estado. Não repita inícios, alternâncias ou GO pendentes após restabelecer a ligação.
As pressões de volume associadas à ligação são libertadas ao desligar. Considere a nova ligação uma nova sessão, mesmo que o endereço não tenha mudado.
Alterar Permitir origens externas no Sound Show tem efeito imediato e desliga os clientes atuais. Após desativar, navegadores de outras origens não podem voltar a ligar-se. Consulte comandos remotos em navegadores personalizados para configuração e restrições do navegador.