مباشر: ضبابية الخلفية تفشل دائمًا في متصفح Brave ("تعذر بدء تشغيل ضبابية الخلفية") - يتم إلغاء تنفيذ .play() لعنصر <video> المنفصل

الملخص

FAO: @Falco :smiling_face_with_sunglasses:
إفصاح عن الذكاء الاصطناعي: تم التحقيق في هذا الخطأ بشكل مستقل (agentically)، وقُدمت الأسباب والحلول المقترحة بواسطة Opus 5.5.

في متصفح Brave، يؤدي تفعيل ضبابية الخلفية (background blur) في غرفة Live إلى ظهور رسالة خطأ دائماً: “تعذر بدء تشغيل ضبابية الخلفية، لذا تم إيقافها.” بينما يعمل نفس المستخدم والمنتدى والغرفة بشكل سليم في متصفح Google Chrome على نفس الجهاز.

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

السبب هو عنصر <video> المخفي الذي ينشئه BackgroundBlurManager#setup() لكنه لا يُدرج أبداً في المستند. يرفض 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
  • Brave (Chromium 155) على Linux، Wayland، بطاقة رسومات Intel؛ تسريع WebGL2 وWebGPU عبر الأجهزة
  • Google Chrome على نفس الجهاز: يعمل

خطوات إعادة الإنتاج

  1. افتح غرفة Live في Brave وشغّل الكاميرا.
  2. فعّل ضبابية الخلفية.
  3. تظهر الرسالة المنبثقة ويتم إيقاف الضبابية.

التشخيص

قمت بتشغيل خط أنابيب الضبابية الخاص بالإضافة خطوة بخطوة في وحدة تحكم Brave (مع نفس مسار الأصل، والنموذج، والوكيل، ووضع التشغيل كما في background-blur.js)، مع تفعيل حماية بصمة المتصفح (fingerprinting protection) في Brave ثم تعطيلها:

الخطوة Brave، حماية البصمة مفعّلة Brave، حماية البصمة معطّلة
استيراد vision_bundle.js، تحميل WASM جيد جيد
ImageSegmenter.createFromOptions، وكلاء GPU وCPU جيد جيد
getUserMedia({ video: true })، حالة المسار جيد، live جيد، live
play() على <video> مكتوم منفصل يحمل بث الكاميرا (ما تفعله الإضافة) AbortError AbortError
play() على <video> من نفس النوع مُضاف إلى document.body (بكسل واحد، شفاف) جيد جيد

لذا فإن MediaPipe وWebGL والكاميرا كلها تعمل بشكل سليم. فقط play() المنفصل يفشل، وحماية بصمة المتصفح في Brave لا تُحدث أي فرق. يعمل Chromium بدون واجهة (Headless) بتشغيل <video> منفصل دون خطأ، وهو ما يتوافق مع عمل Chrome.

الإصلاح المقترح

في plugins/live/assets/javascripts/discourse/lib/live/background-blur.js، داخل الدالة setup(): أضف الفيديو المخفي إلى المستند قبل video.play()، وأزله في 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. الخطأ الحقيقي يتم ابتلاعه. يستخدم #createBackgroundBlur() في local-video-manager.js كتلة 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 في كلتا الحالتين. إضافة فحص WebGL2 إلى isSupported() ستخفي أو تعطّل تحكم الضبابية بدلاً من الفشل بعد أن يقوم المستخدم بتفعيلها. (تمت إعادة الإنتاج في Chromium بدون واجهة عن طريق جعل getContext("webgl*") دالة وهمية، ولم يُرصد ذلك في الاستخدام الفعلي).

شكراً على Live - باستثناء هذا، إنه يعمل بشكل رائع لدينا.