Skip to content

audio: botao 🔄 nunca ve hardware novo — /api/devices le a lista congelada do PortAudio (sem re-init) #37

Description

@caioross

Contexto

O botão 🔄 Atualizar dispositivos (entregue na #23) promete literalmente, no tooltip:

"Re-detecta os dispositivos de áudio sem recarregar a página. Use ao conectar um fone ou renomear o CABLE depois de abrir o painel." (static/i18n.js:17)

Só que a promessa não se sustenta no backend. O caminho é:

refreshDevices() (static/app.js:136) → loadDevices() (static/app.js:110) → GET /api/devices (laguna_server.py:74) → list_devices() (laguna_core.py:712) → sd.query_devices().

O PortAudio enumera os devices uma única vez, no Pa_Initialize (que o sounddevice dispara no primeiro uso do processo) e serve a lista de um cache estático. Chamar sd.query_devices() de novo devolve exatamente a mesma lista congelada. Ou seja: fone plugado depois, VB-CABLE instalado depois, ou "CABLE Output" renomeado para Laguna Translator Mic depois — nada disso aparece. O botão gira o spinner, repopula os selects com os mesmos dados e o usuário conclui que o hardware dele é que está errado.

Sintoma cruel: o passo a passo de setup manda renomear o CABLE — e é justamente o momento em que a lista precisa mudar. A única saída real hoje é reiniciar o servidor (recarregar a página não basta, o processo é o mesmo).

Ninguém re-inicializa o PortAudio no repo: grep -rn "_terminate\|_initialize" --include=*.py . só acha comentários e stubs de teste.

Proposta

Em /api/devices, aceitar um refresh explícito que re-inicialize o PortAudio antes de enumerar:

sd._terminate()
sd._initialize()

Guarda obrigatória — não re-inicializar com worker rodando. _terminate() derruba os streams abertos e, pior, os índices dos devices são reatribuídos na nova enumeração: um worker vivo guarda capture_device/output_devices como int (laguna_core.py:54-56) e passaria a apontar para outro hardware silenciosamente. O servidor já sabe quem está rodando (_workers, laguna_server.py:37) — basta pular o re-init (ou recusar) quando _workers não estiver vazio, e a UI explicar "pare as direções para re-detectar".

Acceptance criteria

  • Com o servidor no ar, instalar/renomear um device (ou plugar um fone) e clicar 🔄 passa a mostrar o device novo/renomeado sem reiniciar o processo — incluindo o badge 🌊 quando o nome vira "Laguna".
  • Com qualquer direção rodando, o refresh não re-inicializa o PortAudio: a captura/saída em andamento continua intacta e a UI informa (chave i18n nova em PT e EN) que é preciso parar para re-detectar.
  • sd._terminate/sd._initialize são API privada do sounddevice: acesso defensivo (getattr + try/except) com fallback para a enumeração simples — versão sem esses símbolos degrada, não quebra o endpoint (a ui: falha do /api/devices no boot deixa a UI morta e muda (WebSocket nunca conecta, nenhum erro visível) #33 já ensinou que /api/devices quebrado mata o boot da UI).
  • Refresh sem worker rodando não derruba a conexão WS nem o estado da UI.
  • Teste em tests_unit/ com o stub de sd (padrão de tests_unit/test_validate_config.py): (a) sem workers → chama re-init e devolve a lista nova; (b) com worker registrado → não chama re-init; (c) sd sem _terminate → devolve a lista mesmo assim, sem exceção.
  • Tooltip/texto do passo a passo continuam verdadeiros depois da mudança (revisar static/i18n.js e o rodapé de setup).

Abordagem

Menor diff que resolve: parâmetro opcional no endpoint (ex.: GET /api/devices?refresh=1) — o boot continua chamando a versão barata, e só o clique no 🔄 pede o re-init. Isso evita pagar Pa_Terminate/Pa_Initialize (centenas de ms no WASAPI) em todo carregamento de página.

Escopo / autonomia

Toca laguna_server.py (contrato REST) → área de quórum, HANDBOOK §7.2. Gate: T1 + pytest tests_unit/ + T3 se mexer em static/.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Melhoria médiaarea:audioDevices, sounddevice, WASAPI loopback, VB-CABLEarea:serverFastAPI, REST/WS, laguna_server

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions