mirror of https://github.com/OpenVidu/openvidu.git
ov-components: Improves virtual background support handling
Adds a more robust mechanism to manage virtual background support, including: - Displaying a warning message when the browser does not support virtual backgrounds. - Disabling background selection buttons when virtual backgrounds are not supported. - Optimizing background processor initialization and attachment for different browsers (handling lazy loading for Firefox). - Centralizing the check for virtual background support in the OpenViduService. This change ensures a better user experience by clearly indicating when virtual backgrounds are unavailable and preventing users from attempting to use an unsupported feature.master
parent
6cfa44c4f1
commit
7208cb3a65
|
|
@ -13,6 +13,13 @@
|
|||
</button>
|
||||
}
|
||||
|
||||
@if (!isVirtualBackgroundSupported()) {
|
||||
<div class="not-supported-message">
|
||||
<p class="warning-title">{{ 'PANEL.BACKGROUND.NOT_SUPPORTED' | translate }}</p>
|
||||
<p class="warning-description">{{ 'PANEL.BACKGROUND.NOT_SUPPORTED_DESCRIPTION' | translate }}</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="effects-container" fxFlex="100%" fxLayoutAlign="space-evenly none">
|
||||
<div>
|
||||
<h4 class="background-title">{{ 'PANEL.BACKGROUND.BLURRED_SECTION' | translate }}</h4>
|
||||
|
|
@ -24,6 +31,7 @@
|
|||
[class.active-effect-btn]="backgroundSelectedId === effect.id"
|
||||
(click)="applyBackground(effect)"
|
||||
[attr.id]="effect.id + '-btn'"
|
||||
[disabled]="!isVirtualBackgroundSupported()"
|
||||
[matTooltip]="
|
||||
effect.type === effectType.NONE
|
||||
? ('PANEL.BACKGROUND.NO_EFFECTS' | translate)
|
||||
|
|
@ -44,7 +52,8 @@
|
|||
class="effect-button"
|
||||
[id]="'effect-' + effect.id"
|
||||
[class.active-effect-btn]="backgroundSelectedId === effect.id"
|
||||
(click)="applyBackground(effect)"
|
||||
[class.disabled]="!isVirtualBackgroundSupported()"
|
||||
(click)="isVirtualBackgroundSupported() && applyBackground(effect)"
|
||||
>
|
||||
<img [src]="effect.thumbnail" />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,26 @@
|
|||
margin: 10px 0;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.not-supported-message {
|
||||
padding: 15px;
|
||||
margin: 10px;
|
||||
background-color: var(--ov-warn-color, #ff9800);
|
||||
border-radius: var(--ov-surface-radius);
|
||||
color: var(--ov-text-surface-color);
|
||||
|
||||
.warning-title {
|
||||
font-weight: 500;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.warning-description {
|
||||
font-size: 0.9em;
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
.effects-container {
|
||||
display: block !important;
|
||||
overflow-y: auto;
|
||||
|
|
@ -33,6 +53,11 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.effect-button.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.active-effect-btn {
|
||||
border: 2px solid var(--ov-accent-action-color);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, EventEmitter, Input, OnInit, Output, Signal } from '@angular/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { BackgroundEffect, EffectType } from '../../../models/background-effect.model';
|
||||
import { PanelType } from '../../../models/panel.model';
|
||||
|
|
@ -23,7 +23,7 @@ export class BackgroundEffectsPanelComponent implements OnInit {
|
|||
effectType = EffectType;
|
||||
backgroundImages: BackgroundEffect[] = [];
|
||||
noEffectAndBlurredBackground: BackgroundEffect[] = [];
|
||||
private backgrounds: BackgroundEffect[];
|
||||
private backgrounds: BackgroundEffect[] = [];
|
||||
private backgroundSubs: Subscription;
|
||||
|
||||
/**
|
||||
|
|
@ -38,6 +38,14 @@ export class BackgroundEffectsPanelComponent implements OnInit {
|
|||
private cd: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Computed signal that reactively tracks if virtual background is supported.
|
||||
* Updates automatically when browser support changes.
|
||||
*/
|
||||
readonly isVirtualBackgroundSupported: Signal<boolean> = computed(() =>
|
||||
this.backgroundService.isVirtualBackgroundSupported()
|
||||
);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.subscribeToBackgroundSelected();
|
||||
this.backgrounds = this.backgroundService.getBackgrounds();
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "没有效果和模糊的背景",
|
||||
"NO_EFFECTS": "没有背景效果",
|
||||
"BLURRED_EFFECT": "模糊的背景",
|
||||
"IMAGES_SECTION": "背景图像"
|
||||
"IMAGES_SECTION": "背景图像",
|
||||
"NOT_SUPPORTED": "此浏览器不支持虚拟背景",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "您的浏览器不支持背景效果。此功能需要 GPU 加速,可能已被禁用或不可用。"
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "录音",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Keine Effekte und unscharfer Hintergrund",
|
||||
"NO_EFFECTS": "Kein Hintergrundeffekt",
|
||||
"BLURRED_EFFECT": "Unscharfer Hintergrund",
|
||||
"IMAGES_SECTION": "Hintergrundbilder"
|
||||
"IMAGES_SECTION": "Hintergrundbilder",
|
||||
"NOT_SUPPORTED": "Virtuelle Hintergründe werden in diesem Browser nicht unterstützt",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Ihr Browser unterstützt keine Hintergrundeffekte. Diese Funktion erfordert GPU-Beschleunigung, die möglicherweise deaktiviert oder nicht verfügbar ist."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Aufnahme",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "No effects and blurred background",
|
||||
"NO_EFFECTS": "No background effect",
|
||||
"BLURRED_EFFECT": "Blurred background",
|
||||
"IMAGES_SECTION": "Background images"
|
||||
"IMAGES_SECTION": "Background images",
|
||||
"NOT_SUPPORTED": "Virtual backgrounds are not supported in this browser",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Your browser does not support background effects. This feature requires GPU acceleration which may be disabled or unavailable."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Recording",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Sin efectos y fondo desenfocado",
|
||||
"NO_EFFECTS": "Sin efecto",
|
||||
"BLURRED_EFFECT": "Fondo desenfocado",
|
||||
"IMAGES_SECTION": "Imágenes de fondo"
|
||||
"IMAGES_SECTION": "Imágenes de fondo",
|
||||
"NOT_SUPPORTED": "Los efectos de fondo virtuales no son compatibles con este navegador",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Tu navegador no admite efectos de fondo. Esta función requiere aceleración GPU que puede estar deshabilitada o no disponible."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Grabación",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Aucun effet et arrière-plan flou",
|
||||
"NO_EFFECTS": "Aucun effet de fond",
|
||||
"BLURRED_EFFECT": "Arrière-plan flou",
|
||||
"IMAGES_SECTION": "Images d'arrière-plan"
|
||||
"IMAGES_SECTION": "Images d'arrière-plan",
|
||||
"NOT_SUPPORTED": "Les arrière-plans virtuels ne sont pas pris en charge dans ce navigateur",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Votre navigateur ne prend pas en charge les effets d'arrière-plan. Cette fonctionnalité nécessite l'accélération GPU qui peut être désactivée ou non disponible."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Enregistrement",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "कोई प्रभाव नहीं है और पृष्ठभूमि धुंधली है",
|
||||
"NO_EFFECTS": "कोई पृष्ठभूमि प्रभाव नहीं है",
|
||||
"BLURRED_EFFECT": "पृष्ठभूमि धुंधली है",
|
||||
"IMAGES_SECTION": "पृष्ठभूमि छवियां"
|
||||
"IMAGES_SECTION": "पृष्ठभूमि छवियां",
|
||||
"NOT_SUPPORTED": "इस ब्राउज़र में वर्चुअल बैकग्राउंड समर्थित नहीं है",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "आपका ब्राउज़र बैकग्राउंड इफेक्ट्स का समर्थन नहीं करता है। इस सुविधा के लिए GPU त्वरण की आवश्यकता है जो अक्षम या अनुपलब्ध हो सकता है।"
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "रिकॉर्डिंग",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Nessun effetto e sfondo sfocato",
|
||||
"NO_EFFECTS": "Nessun effetto di sfondo",
|
||||
"BLURRED_EFFECT": "Sfondo sfocato",
|
||||
"IMAGES_SECTION": "Immagini di sfondo"
|
||||
"IMAGES_SECTION": "Immagini di sfondo",
|
||||
"NOT_SUPPORTED": "Gli sfondi virtuali non sono supportati in questo browser",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Il tuo browser non supporta gli effetti di sfondo. Questa funzione richiede l'accelerazione GPU che potrebbe essere disabilitata o non disponibile."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Registrazione",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "エフェクトなし、ぼやけた背景",
|
||||
"NO_EFFECTS": "背景エフェクトなし",
|
||||
"BLURRED_EFFECT": "ぼやけた背景",
|
||||
"IMAGES_SECTION": "背景画像"
|
||||
"IMAGES_SECTION": "背景画像",
|
||||
"NOT_SUPPORTED": "このブラウザでは仮想背景はサポートされていません",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "お使いのブラウザは背景効果をサポートしていません。この機能にはGPUアクセラレーションが必要ですが、無効化されているか利用できません。"
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "レコーディング",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Geen effecten en onscherpe achtergrond",
|
||||
"NO_EFFECTS": "Geen achtergrondeffect",
|
||||
"BLURRED_EFFECT": "Onscherpe achtergrond",
|
||||
"IMAGES_SECTION": "Achtergrondafbeeldingen"
|
||||
"IMAGES_SECTION": "Achtergrondafbeeldingen",
|
||||
"NOT_SUPPORTED": "Virtuele achtergronden worden niet ondersteund in deze browser",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Uw browser ondersteunt geen achtergrondeffecten. Deze functie vereist GPU-versnelling die mogelijk uitgeschakeld of niet beschikbaar is."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Opname",
|
||||
|
|
|
|||
|
|
@ -120,7 +120,9 @@
|
|||
"BLURRED_SECTION": "Sem efeitos e fundo desfocado",
|
||||
"NO_EFFECTS": "Sem efeito de fundo",
|
||||
"BLURRED_EFFECT": "Fundo desfocado",
|
||||
"IMAGES_SECTION": "Imagens de fundo"
|
||||
"IMAGES_SECTION": "Imagens de fundo",
|
||||
"NOT_SUPPORTED": "Fundos virtuais não são suportados neste navegador",
|
||||
"NOT_SUPPORTED_DESCRIPTION": "Seu navegador não suporta efeitos de fundo. Este recurso requer aceleração de GPU que pode estar desabilitada ou não disponível."
|
||||
},
|
||||
"RECORDING": {
|
||||
"TITLE": "Gravação",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { BackgroundProcessor, /*BackgroundProcessorWrapper,*/ SwitchBackgroundProcessorOptions } from '@livekit/track-processors';
|
||||
import { Injectable, signal, Signal } from '@angular/core';
|
||||
import {
|
||||
BackgroundProcessor,
|
||||
supportsBackgroundProcessors,
|
||||
supportsModernBackgroundProcessors,
|
||||
/*BackgroundProcessorWrapper,*/ SwitchBackgroundProcessorOptions
|
||||
} from '@livekit/track-processors';
|
||||
import {
|
||||
AudioCaptureOptions,
|
||||
ConnectionState,
|
||||
createLocalTracks,
|
||||
CreateLocalTracksOptions,
|
||||
E2EEOptions,
|
||||
ExternalE2EEKeyProvider,
|
||||
|
|
@ -13,14 +19,12 @@ import {
|
|||
RoomOptions,
|
||||
Track,
|
||||
VideoCaptureOptions,
|
||||
VideoPresets,
|
||||
createLocalTracks
|
||||
VideoPresets
|
||||
} from 'livekit-client';
|
||||
import { ILogger } from '../../models/logger.model';
|
||||
import { OpenViduComponentsConfigService } from '../config/directive-config.service';
|
||||
import { DeviceService } from '../device/device.service';
|
||||
import { LoggerService } from '../logger/logger.service';
|
||||
import { PlatformService } from '../platform/platform.service';
|
||||
import { StorageService } from '../storage/storage.service';
|
||||
|
||||
// TODO: Remove this once livekit-client exports it
|
||||
|
|
@ -58,8 +62,20 @@ export class OpenViduService {
|
|||
/**
|
||||
* Background processor for video tracks. Initialized in disabled mode.
|
||||
* This processor is shared between prejoin and in-room states.
|
||||
* Only initialized if browser supports background processing (GPU available).
|
||||
*/
|
||||
private backgroundProcessor: BackgroundProcessorWrapper;
|
||||
private backgroundProcessor?: BackgroundProcessorWrapper;
|
||||
|
||||
/**
|
||||
* Signal to track if background processor is supported (requires GPU).
|
||||
* Set to false if browser doesn't support it or processor initialization fails.
|
||||
*/
|
||||
private _isBackgroundProcessorSupported = signal(false);
|
||||
|
||||
/**
|
||||
* Public readonly signal for background processor support status.
|
||||
*/
|
||||
readonly isBackgroundProcessorSupported: Signal<boolean> = this._isBackgroundProcessorSupported.asReadonly();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
|
@ -69,11 +85,33 @@ export class OpenViduService {
|
|||
private deviceService: DeviceService,
|
||||
private storageService: StorageService,
|
||||
private configService: OpenViduComponentsConfigService,
|
||||
private platformService: PlatformService
|
||||
) {
|
||||
this.log = this.loggerSrv.get('OpenViduService');
|
||||
// this.isSttReadyObs = this._isSttReady.asObservable();
|
||||
this.backgroundProcessor = BackgroundProcessor({ mode: 'disabled' });
|
||||
|
||||
// Check if browser supports background processors
|
||||
if (!supportsBackgroundProcessors()) {
|
||||
this.log.w('Background processors not supported in this browser (GPU may be disabled)');
|
||||
this._isBackgroundProcessorSupported.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Only initialize processor immediately for browsers supporting modern processors
|
||||
// Browsers without modern support (e.g., Firefox) will initialize on-demand
|
||||
if (supportsModernBackgroundProcessors()) {
|
||||
try {
|
||||
this.backgroundProcessor = BackgroundProcessor({ mode: 'disabled' });
|
||||
this._isBackgroundProcessorSupported.set(true);
|
||||
this.log.d('Background processor initialized at startup (modern processors supported)');
|
||||
} catch (error: any) {
|
||||
this.log.w('Failed to initialize background processor:', error?.message || error);
|
||||
this._isBackgroundProcessorSupported.set(false);
|
||||
}
|
||||
} else {
|
||||
// Mark as supported but don't initialize yet - will be created on-demand
|
||||
this._isBackgroundProcessorSupported.set(true);
|
||||
this.log.d('Background processors supported but not modern - will initialize on-demand');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -275,6 +313,8 @@ export class OpenViduService {
|
|||
return this.localTracks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Switches the background mode on the local video track.
|
||||
* Works both in prejoin and in-room states.
|
||||
|
|
@ -285,20 +325,36 @@ export class OpenViduService {
|
|||
* @internal
|
||||
*/
|
||||
async switchBackgroundMode(options: SwitchBackgroundProcessorOptions): Promise<void> {
|
||||
// For Firefox, attach processor only when an effect is activated
|
||||
if (this.platformService.isFirefox()) {
|
||||
await this.handleFirefoxProcessor(options.mode);
|
||||
if (!this.isBackgroundProcessorSupported()) {
|
||||
this.log.w('Background processor not supported (GPU disabled). Virtual background is disabled.');
|
||||
return;
|
||||
}
|
||||
|
||||
await this.backgroundProcessor.switchTo(options);
|
||||
this.log.d('Background mode switched:', options);
|
||||
try {
|
||||
// For browsers without modern processor support: attach processor on-demand when effect is activated
|
||||
if (!supportsModernBackgroundProcessors()) {
|
||||
await this.handleLazyProcessorAttachment(options.mode);
|
||||
}
|
||||
|
||||
// If processor exists, switch mode (either pre-initialized or just created on-demand)
|
||||
if (this.backgroundProcessor) {
|
||||
await this.backgroundProcessor.switchTo(options);
|
||||
this.log.d('Background mode switched:', options);
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.log.e('Failed to switch background mode:', error?.message || error);
|
||||
this._isBackgroundProcessorSupported.set(false);
|
||||
// Don't throw - gracefully disable virtual background instead of crashing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the background processor handling for Firefox browser.
|
||||
* Handles lazy processor attachment for browsers without modern processor support.
|
||||
* Creates and attaches processor on-demand when effect is activated.
|
||||
* This is used for browsers like Firefox that don't support modern background processors.
|
||||
* @internal
|
||||
*/
|
||||
private async handleFirefoxProcessor(mode: SwitchBackgroundProcessorOptions['mode']): Promise<void> {
|
||||
private async handleLazyProcessorAttachment(mode: SwitchBackgroundProcessorOptions['mode']): Promise<void> {
|
||||
const videoTrack = await this.getVideoTrack();
|
||||
if (!videoTrack) return;
|
||||
|
||||
|
|
@ -306,13 +362,25 @@ export class OpenViduService {
|
|||
const isDisabled = mode === 'disabled';
|
||||
|
||||
if (!isDisabled && !hasProcessor) {
|
||||
this.log.d('Firefox: Attaching processor on effect activation');
|
||||
await videoTrack.setProcessor(this.backgroundProcessor);
|
||||
try {
|
||||
// Create processor on-demand if not already created
|
||||
if (!this.backgroundProcessor) {
|
||||
this.log.d('Creating background processor on-demand');
|
||||
this.backgroundProcessor = BackgroundProcessor({ mode: 'disabled' });
|
||||
}
|
||||
|
||||
this.log.d('Attaching processor on effect activation (lazy loading)');
|
||||
await videoTrack.setProcessor(this.backgroundProcessor);
|
||||
} catch (error: any) {
|
||||
this.log.w('Failed to attach background processor (GPU may be disabled):', error?.message || error);
|
||||
this._isBackgroundProcessorSupported.set(false);
|
||||
// Continue without crashing - virtual background will be disabled
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDisabled && hasProcessor) {
|
||||
this.log.d('Firefox: Stopping processor on effect deactivation');
|
||||
this.log.d('Stopping processor on effect deactivation');
|
||||
await videoTrack.stopProcessor();
|
||||
}
|
||||
}
|
||||
|
|
@ -390,15 +458,24 @@ export class OpenViduService {
|
|||
}
|
||||
|
||||
// Apply background processor to video track (initialized in disabled mode)
|
||||
// For Firefox: skip processor attachment to avoid performance issues (applied only when effect is activated)
|
||||
// For other browsers: attach processor for smooth transitions
|
||||
// For browsers with modern processor support: attach processor immediately for smooth transitions
|
||||
// For browsers without modern support: skip attachment, will be applied on-demand when effect is activated
|
||||
const videoTrack = newLocalTracks.find((t) => t.kind === Track.Kind.Video) as LocalVideoTrack | undefined;
|
||||
debugger;
|
||||
if (videoTrack && !this.platformService.isFirefox()) {
|
||||
await videoTrack.setProcessor(this.backgroundProcessor);
|
||||
this.log.d('Background processor applied to newly created video track');
|
||||
} else if (videoTrack && this.platformService.isFirefox()) {
|
||||
this.log.d('Firefox detected: skipping processor attachment for better performance');
|
||||
if (videoTrack && supportsModernBackgroundProcessors()) {
|
||||
if (this.isBackgroundProcessorSupported() && this.backgroundProcessor) {
|
||||
try {
|
||||
await videoTrack.setProcessor(this.backgroundProcessor);
|
||||
this.log.d('Background processor applied to newly created video track');
|
||||
} catch (error: any) {
|
||||
this.log.w('Failed to apply background processor (GPU may be disabled):', error?.message || error);
|
||||
this._isBackgroundProcessorSupported.set(false);
|
||||
// Continue without crashing - virtual background will be disabled
|
||||
}
|
||||
} else {
|
||||
this.log.d('Background processor not supported (GPU disabled or not available)');
|
||||
}
|
||||
} else if (videoTrack && !supportsModernBackgroundProcessors()) {
|
||||
this.log.d('Modern background processors not supported - will apply processor on-demand when effect is activated');
|
||||
}
|
||||
|
||||
// Mute tracks if devices are disabled
|
||||
|
|
|
|||
|
|
@ -406,10 +406,9 @@ export class ParticipantService {
|
|||
// Update Signal - create new reference to trigger reactivity
|
||||
// The Observable will automatically emit via toObservable()
|
||||
if (this.localParticipant) {
|
||||
const updatedParticipant = Object.assign(
|
||||
Object.create(Object.getPrototypeOf(this.localParticipant)),
|
||||
{ ...this.localParticipant }
|
||||
);
|
||||
const updatedParticipant = Object.assign(Object.create(Object.getPrototypeOf(this.localParticipant)), {
|
||||
...this.localParticipant
|
||||
});
|
||||
this.localParticipantWritableSignal.set(updatedParticipant);
|
||||
} else {
|
||||
this.localParticipantWritableSignal.set(undefined);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { computed, Injectable, Signal } from '@angular/core';
|
||||
import { SwitchBackgroundProcessorOptions } from '@livekit/track-processors';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { BackgroundEffect, EffectType } from '../../models/background-effect.model';
|
||||
|
|
@ -59,6 +59,14 @@ export class VirtualBackgroundService {
|
|||
return this.backgrounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computed signal that checks if virtual background is supported (requires GPU).
|
||||
* Reactively tracks the support status from OpenViduService.
|
||||
*/
|
||||
readonly isVirtualBackgroundSupported: Signal<boolean> = computed(() =>
|
||||
this.openviduService.isBackgroundProcessorSupported()
|
||||
);
|
||||
|
||||
isBackgroundApplied(): boolean {
|
||||
const bgSelected = this.backgroundIdSelected.getValue();
|
||||
return !!bgSelected && bgSelected !== 'no_effect';
|
||||
|
|
@ -80,6 +88,12 @@ export class VirtualBackgroundService {
|
|||
* The background processor is centralized in OpenViduService for consistency.
|
||||
*/
|
||||
async applyBackground(bg: BackgroundEffect) {
|
||||
// Check if virtual background is supported before proceeding
|
||||
if (!this.isVirtualBackgroundSupported()) {
|
||||
this.log.w('Virtual background not supported (GPU disabled). Skipping background application.');
|
||||
return;
|
||||
}
|
||||
|
||||
// If the background is already applied, do nothing
|
||||
if (this.backgroundIsAlreadyApplied(bg.id)) return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue