Pitch: legendas traduzidas ao vivo em chamadas no navegador, com o áudio da aba capturado por uma extensão MV3
Eu sou o autor do projeto e desenvolvo sozinho. O link no final passa por um redirecionamento meu que só conta cliques.
A extensão mostra legendas traduzidas em tempo real durante uma chamada no Meet, no Zoom ou no Teams pelo navegador, sem nenhum bot na reunião. Abaixo, as três partes que deram mais trabalho.
1. Capturar o áudio da aba no Manifest V3
No MV3 o service worker não tem Web Audio, então a captura fica em dois lugares. O service worker chama chrome.tabCapture.getMediaStreamId({ targetTabId }), que devolve só um id, e cria um documento offscreen com reasons: ['USER_MEDIA']. Lá dentro o id vira stream no getUserMedia com chromeMediaSource: 'tab', e um AudioWorkletNode junta os canais em mono e manda Int16 PCM em blocos de 4096 amostras.
Duas coisas custaram tempo. O stream precisa ser ligado de volta em audioCtx.destination, senão a captura silencia a aba e a pessoa para de ouvir a própria reunião. E o erro "Cannot capture a tab with an active stream" aparece quando o stream anterior não foi liberado, e não sai nem recarregando a página: o jeito foi fechar o documento offscreen e consultar chrome.tabCapture.getCapturedTabs() até a aba sair de active.
Contra o getDisplayMedia() numa página comum: aqui não aparece o seletor de tela, mas a extensão precisa ter sido invocada naquela aba (activeTab) e só pega o áudio da aba.
2. Dois provedores custaram muito mais que um
A primeira versão usava um serviço para reconhecimento e outro para tradução. Para a tradução acompanhar a fala, os resultados parciais também iam para o tradutor, e a mesma frase era traduzida duas ou três vezes. Uma hora de chamada saía por volta de US$ 2,55, acima do que os planos cobriam.
Troquei por um provedor que devolve transcrição e tradução no mesmo stream, com chave temporária emitida pelo servidor. Pela fatura real, hoje uma hora custa uns US$ 0,15. O preço disso é atraso: a legenda final chega em alguns segundos, contra uns dois antes. E o provedor não separa pt-BR de pt-PT, as duas viram pt.
3. O cronômetro contava errado
O tempo começava quando a conexão abria, não quando chegava a primeira legenda, então numa aba sem som os minutos eram gastos à toa. Achei olhando as minhas próprias estatísticas, agora a contagem começa com o primeiro resultado real.
Limites: só o áudio da aba do navegador, app desktop e celular não, e a legenda final demora alguns segundos.
Críticas sobre a parte técnica são bem-vindas, principalmente sobre a captura no MV3: https://gettrippi.app/go/tabnews_pitch