Ao vivo: desfocagem de fundo sempre falha no Brave Browser ("Não foi possível iniciar a desfocagem de fundo") - play() do <video> desconectado é interrompido

Resumo

FAO: @Falco :smiling_face_with_sunglasses:
Divulgação de IA: Este bug foi investigado de forma autônoma e a causa e a solução foram sugeridas pelo Opus 5.5.

No navegador Brave, ao ativar o desfoque de fundo em uma sala Live, sempre aparece um toast de erro: “Não foi possível iniciar o desfoque de fundo, então ele foi desativado.” O mesmo usuário, fórum e sala funcionam normalmente no Google Chrome na mesma máquina.

error: "Background blur couldn't be started, so it was turned off."

A causa é o elemento <video> oculto que BackgroundBlurManager#setup() cria, mas nunca insere no documento. O Brave rejeita o play() nele com:

AbortError: The play() request was interrupted because the media was removed from the document.

Inserir o elemento no documento (de forma invisível) antes do play() faz com que funcione no Brave.

Ambiente

  • Discourse 2026.10.0-latest.1 (568a006ad8), plugin Live incluído, discourse_voice_assets 0.2.0
  • Brave (Chromium 155) no Linux, Wayland, GPU Intel; WebGL2 e WebGPU acelerados por hardware
  • Google Chrome na mesma máquina: funciona

Passos para reproduzir

  1. Abra uma sala Live no Brave e ligue a câmera.
  2. Ative o desfoque de fundo.
  3. O toast aparece e o desfoque é desligado.

Diagnóstico

Executei o pipeline de desfoque do próprio plugin passo a passo no console do Brave (mesmo caminho de asset, modelo, delegado e modo de execução que background-blur.js), com a proteção contra fingerprinting do Brave ativada e depois desativada:

Etapa Brave, proteção contra fingerprinting ativada Brave, proteção contra fingerprinting desativada
Importação de vision_bundle.js, carregamento WASM ok ok
ImageSegmenter.createFromOptions, delegados GPU e CPU ok ok
getUserMedia({ video: true }), estado da track ok, live ok, live
play() em um <video> mudo desconectado com o stream da câmera (o que o plugin faz) AbortError AbortError
play() no mesmo tipo de <video> anexado a document.body (1px, transparente) ok ok

Ou seja, MediaPipe, WebGL e a câmera estão todos funcionando corretamente. Apenas o play() desconectado falha, e a proteção contra fingerprinting do Brave não faz diferença. O Chromium headless reproduz um <video> desconectado sem erro, o que está de acordo com o fato de funcionar no Chrome.

Correção sugerida

Em plugins/live/assets/javascripts/discourse/lib/live/background-blur.js, em setup(): anexe o vídeo oculto ao documento antes de video.play() e remova-o em teardown(). Por exemplo:

video.setAttribute("aria-hidden", "true");
video.style.cssText =
  "position:fixed;width:1px;height:1px;opacity:0;pointer-events:none";
document.body.appendChild(video);
// ... await video.play() como agora ...

// teardown():
this.#video?.remove();

Até onde consigo ver, este é o único lugar no plugin que reproduz um elemento de mídia desconectado.

Duas observações relacionadas

  1. O erro real é ignorado. #createBackgroundBlur() em local-video-manager.js usa um catch {} simples e chama liveLog.warn("[live] failed to start background blur") sem o erro. Mesmo com live_verbose_logging ativado, o console nunca diz por que o desfoque falhou. Passar o erro capturado para liveLog.warn (que já o sanitiza) teria exposto o erro mais rapidamente.

  2. O desfoque é oferecido onde nunca pode funcionar. BackgroundBlurManager.isSupported() verifica apenas canvas.captureStream e WebAssembly. Em um navegador sem WebGL, o segmentador do MediaPipe falha com ambos os delegados GPU e CPU (Service "kGpuService" ... cannot be created: emscripten_webgl_create_context() returned error 0), porque o pós-processador de segmentação precisa de um contexto GL de qualquer maneira. Adicionar uma verificação de WebGL2 em isSupported() ocultaria ou desabilitaria o controle de desfoque em vez de falhar após o usuário ativá-lo. (Reproduzido no Chromium headless fazendo stub de getContext("webgl*"), não visto no mundo real.)

Obrigado pelo Live - além disso, está funcionando muito bem para nós.

1 curtida

Parece bom à primeira vista. Você gostaria de enviar um PR com a correção?