直播:Brave 浏览器中背景模糊始终失败(“无法启动背景模糊”)- 分离的 <video>.play() 被中止

摘要

FAO: @Falco :smiling_face_with_sunglasses:
AI 披露:此 bug 由代理自动调查,原因及修复建议由 Opus 5.5 提供。

在 Brave 浏览器中,在 Live 房间开启背景模糊功能时,始终会显示错误提示:“无法启动背景模糊,因此已将其关闭。” 在同一台机器上,使用 Google Chrome 访问相同的用户、论坛和房间则运行正常。

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

原因在于 BackgroundBlurManager#setup() 创建但从未插入文档的隐藏 <video> 元素。Brave 拒绝在其上执行 play(),并抛出以下错误:

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

在调用 play() 之前将该元素(不可见地)插入文档即可解决 Brave 中的问题。

环境

  • Discourse 2026.10.0-latest.1 (568a006ad8),捆绑的 Live 插件,discourse_voice_assets 0.2.0
  • Linux 系统上的 Brave (Chromium 155),Wayland,Intel GPU;WebGL2 和 WebGPU 硬件加速已启用
  • 同一台机器上的 Google Chrome:运行正常

复现步骤

  1. 在 Brave 中打开一个 Live 房间并打开摄像头。
  2. 启用背景模糊。
  3. 出现提示框且模糊功能被关闭。

诊断

我在 Brave 控制台中逐步运行了插件自身的模糊处理流程(与 background-blur.js 使用相同的资源路径、模型、委托和运行模式),分别测试了开启和关闭 Brave 指纹保护的情况:

步骤 Brave,开启指纹保护 Brave,关闭指纹保护
vision_bundle.js 导入,WASM 加载 ok ok
ImageSegmenter.createFromOptions,GPU 和 CPU 委托 ok ok
getUserMedia({ video: true }),轨道状态 ok,live ok,live
对带有摄像头流的分离静音 <video> 执行 play()(即插件当前的做法) AbortError AbortError
对追加到 document.body 的同类型 <video>(1px,透明)执行 play() ok ok

因此,MediaPipe、WebGL 和摄像头均无问题。只有分离状态的 play() 失败,而 Brave 的指纹保护设置对此没有影响。无头 Chromium 可以无错误地播放分离的 <video>,这与 Chrome 表现一致。

建议修复方案

在 plugins/live/assets/javascripts/discourse/lib/live/background-blur.js 的 setup() 中:在 video.play() 之前将隐藏的 video 添加到文档中,并在 teardown() 中移除它。例如:

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() as now ...

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

据我观察,这是插件中唯一播放分离媒体元素的地方。

两个相关观察

  1. 真正的错误被吞没了。 local-video-manager.js 中的 #createBackgroundBlur() 使用了空的 catch {},并调用 liveLog.warn("[live] failed to start background blur") 但未包含错误信息。即使启用了 live_verbose_logging,控制台也从未说明模糊失败的原因。将捕获的错误传递给 liveLog.warn(该方法已对其进行清理)本可以让错误更快暴露出来。

  2. 在不支持的环境中也提供了模糊选项。 BackgroundBlurManager.isSupported() 仅检查 canvas.captureStream 和 WebAssembly。在没有 WebGL 的浏览器中,MediaPipe 的分段器在使用 GPU 和 CPU 委托时都会失败(Service "kGpuService" ... cannot be created: emscripten_webgl_create_context() returned error 0),因为分段后处理器无论如何都需要 GL 上下文。在 isSupported() 中添加 WebGL2 检查可以在用户开启该功能之前隐藏或禁用模糊控件,而不是让用户开启后才失败。(通过桩函数模拟 getContext("webgl*") 在无头 Chromium 中复现,实际环境中未见此情况。)

感谢 Live - 除了这个问题之外,它在我们的使用中运行良好。

2 个赞

乍一看,这看起来不错。你想提交一个包含修复的 PR 吗?

1 个赞

即将提交!

3 个赞

谢谢,PR 已合并!

3 个赞