Skip to content

feat(light): bandeja com apertar para falar, indicador de fala e volume por participante - #893

Merged
lucastaonline merged 6 commits into
mainfrom
feat/light-functional
Nov 9, 2026
Merged

lucastaonline merged 6 commits into
mainfrom
feat/light-functional

Conversation

@JelielSantos

Copy link
Copy Markdown
Collaborator

Parte da #658 (Prioridade 2). Junta o #885 (fala e push-to-talk) e o #892 (volume por participante) e liga tudo na bandeja, para o Light ser usado no dia a dia sem mandar comandos JSON. Substitui os dois PRs.

Para quem usa

  • Apertar para falar no menu, com a tecla escolhida por --ptt-key (F13, Mouse4, RightControl…) e salva no perfil. Não há tecla padrão, para não tomar uma tecla de jogo.
  • Na chamada: lista quem está na chamada, marca quem está falando e oferece o volume de cada pessoa em predefinições de 0 a 200%, lembrado nas próximas chamadas.
  • Ícone verde claro enquanto você fala.

Como funciona

Núcleo

  • Fala: remotos pelo nível RFC 6464 do cabeçalho RTP, lido a cada 100 ms só durante a chamada; local por um medidor intercalado no PolicyAudioDevice, sem cópia nem alocação.
  • PTT: track->set_enabled, com a captura aberta para não atrasar a fala. Mute, deafen e restrições do servidor continuam prevalecendo.
  • Volume: ganho do RemoteAudioSource antes da mixagem, sem nó extra e sem custo em 100%.
  • Comandos e eventos: set-input-mode, ptt, set-ptt-key, set-volume; eventos speaking, input-mode, push-to-talk-key, participant-volume e participants; members no state; modo de entrada e tecla no authenticated. A bandeja continua seguindo só por eventos, como na feat(light): adicionar interface de bandeja ao núcleo nativo #750.

Bandeja

  • Modelo e controlador sem dependência de plataforma: decidem quando a tecla deve ser observada (em chamada e no modo PTT) e transformam a repetição automática do teclado num único aperto. Se o hook sumir com a tecla segurada, a soltura é enviada só quando o núcleo ainda a aceitaria.
  • Windows: WH_KEYBOARD_LL, ou WH_MOUSE_LL só para Mouse4/Mouse5, já que o hook de mouse é chamado a cada movimento do ponteiro. Fica na thread da interface e nunca consome a tecla.
  • macOS: addGlobalMonitorForEventsMatchingMask, com o pedido de Acessibilidade feito uma vez e o aviso no menu. Modificadores da direita via flagsChanged e bits NX_DEVICER*.

O commit fix(light) corrige o que derrubou o macOS no CI do #892: o clang com -Wmissing-field-initializers acusava a inicialização parcial do ProfileSettings.

Sem mudança de protocolo: não é major.

Testes (Windows x64, local)

  • npm run test:light:native: 35 aprovados, 4 ignorados por plataforma. Novos casos de modelo e controlador da bandeja: tecla só observada em chamada e em PTT; mouse vs teclado; repetição; soltura ao remover o hook; quem fala; volumes; tabela de teclas. Também perfil com inputMode, userVolumes e pushToTalkKey.
  • npm run test:light:voice: 31 aprovados, 1 ignorado. Fala e PTT, participants, set-ptt-key e volume, todos em P2P e SFU.
  • Smoke manual do hook real (fora da suíte): monky-light.exe --tray --ptt-key F13 numa chamada, com F13 injetado por keybd_event. Um aperto, mesmo com repetição, abre e fecha a transmissão; fora da chamada o hook não existe.

Ainda falta

  • macOS real: monitor global, Acessibilidade e símbolos.
  • Chamada audível com pessoas.
  • measure:light.

Roteiro manual em apps/light/QA.md §6.22–6.30.

🤖 Generated with Claude Code

JelielSantos and others added 6 commits November 6, 2026 22:40
O núcleo passa a emitir `speaking` (sessionId, speaking) para cada participante,
inclusive o próprio usuário. Como no cliente completo, nada é publicado no
servidor: os remotos usam o nível RFC 6464 que o remetente já põe no cabeçalho
RTP, lido a cada 100 ms só durante a chamada; o local é medido por um
AudioTransport intercalado no PolicyAudioDevice, sem cópia nem alocação.
Limiar de -40 dBov e 400 ms de silêncio antes de encerrar a fala.

`set-input-mode` (voice_activity | push_to_talk) é salvo no perfil e `ptt`
abre/fecha a transmissão. A captura continua aberta com a tecla solta para a
fala começar sem atraso; a faixa envia silêncio. Mute, deafen e restrições do
servidor continuam prevalecendo.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…do cliente

No runner macOS Intel a Alice já falava, sozinha na chamada SFU, antes de
bob.join() retornar; o evento ficava antes do ponto de partida da espera.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nky Light

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`set-volume` ajusta de 0 a 200% o volume de uma sessão de voz, com a mesma
escala e chave (sessionId) do controle deslizante do cliente completo. É uma
preferência local, salva no perfil, aplicada na chamada atual e nas próximas,
em P2P e SFU, e emite `participant-volume`; `stats` traz `userVolumes` das
sessões da chamada.

O ganho é o do RemoteAudioSource do WebRTC, aplicado ao fluxo decodificado
antes da mixagem: sem processamento extra e sem custo em 100%. O perfil guarda
até 256 sessões alteradas, e voltar a 100 libera a entrada.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing-field-initializers

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ndeja

A bandeja passa a usar o núcleo de fala, push-to-talk e volume:

- item `Apertar para falar`, que alterna o modo de entrada e mostra a tecla;
- submenu `Na chamada` com quem está falando e o volume de cada pessoa em
  predefinições de 0 a 200%;
- ícone verde claro enquanto o próprio usuário fala.

A tecla é escolhida com `--ptt-key` (ou `set-ptt-key`) e salva no perfil, sem
padrão para não tomar uma tecla de jogo. O atalho global só existe enquanto
pode transmitir (em chamada e no modo apertar para falar): hook de baixo nível
do teclado, ou do mouse para Mouse4/Mouse5, no Windows; monitor global do
AppKit no macOS, que exige a autorização de Acessibilidade. A tecla nunca é
consumida e a repetição automática vira um único aperto.

O núcleo publica `members` no `state` e o evento `participants`, e inclui o
modo de entrada e a tecla no `authenticated`, para a bandeja seguir só por
eventos, como na #750.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JelielSantos

Copy link
Copy Markdown
Collaborator Author

@lucastaonline quando puder, a revisão do Monky Light está em três PRs empilhados. Revisar nesta ordem ajuda, porque cada um depende do anterior:

  1. feat(light): bandeja com apertar para falar, indicador de fala e volume por participante #893 (este, base main): fala, apertar para falar e volume por participante na bandeja. CI todo verde. Pontos que valem um olhar com calma:
    • hooks globais de teclado/mouse (tray_windows.cpp) e o monitor do AppKit (tray_macos.mm), que só existem enquanto podem transmitir;
    • deduplicação e soltura da tecla no TrayController.
  2. feat(light): abrir o Monky Light com duplo clique, sem linha de comando #894 (sobre o feat(light): bandeja com apertar para falar, indicador de fala e volume por participante #893): abrir com duplo clique, com janela de conexão. A decisão principal: a senha continua só em memória, e uma recusa do servidor reabre a janela.
  3. feat(light): iniciar o Monky Light com o sistema, pela bandeja #895 (sobre o feat(light): abrir o Monky Light com duplo clique, sem linha de comando #894): Iniciar com o sistema, desligado por padrão.

Depois de cada merge eu faço o rebase do seguinte para a main, e o CI dele passa a rodar no PR. Os detalhes de cada um estão na descrição do PR e nos comentários da #658.

@lucastaonline
lucastaonline merged commit 6f22ccf into main Nov 9, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants