Files
ChatApp/apps/desktop/src/lib/videoBlur.ts
T
byGalax 1303c8e26f feat: backup/restore, user profile popover, image compress, video blur, wake lock
- backup/restore dialog + user profile popover components
- image compression, video blur, wake lock utilities
- message cache + conversation messages hook refinements
- call context, active speakers, screen share dialog tweaks
- audio + screen share settings persistence
- refreshed app icons (smaller sizes) across all platforms
2026-04-21 12:11:09 +02:00

68 lines
2.3 KiB
TypeScript

// Background-blur processor wrapper. LiveKit's `@livekit/track-processors`
// ships a MediaPipe-based selfie-segmentation pipeline that keeps the
// foreground sharp and blurs the background. The model (~1.5MB) downloads
// lazily on first activation, so users who never enable blur don't pay
// for it.
//
// attach/detach hide behind a guard so repeated toggles don't create a
// stack of processors — `setProcessor(null)` tears down the WebGL context
// and frees the GPU surface.
import type { LocalParticipant, LocalVideoTrack } from 'livekit-client';
import { Track } from 'livekit-client';
let cachedProcessor: unknown = null;
async function getProcessor(): Promise<unknown> {
if (cachedProcessor) return cachedProcessor;
const mod = (await import('@livekit/track-processors')) as {
BackgroundBlur?: (radius?: number) => unknown;
};
if (!mod.BackgroundBlur) {
throw new Error('BackgroundBlur not exported by @livekit/track-processors');
}
cachedProcessor = mod.BackgroundBlur(12);
return cachedProcessor;
}
function getCameraTrack(lp: LocalParticipant): LocalVideoTrack | null {
const pub = lp.getTrackPublication(Track.Source.Camera);
const track = pub?.track;
if (!track) return null;
return track as LocalVideoTrack;
}
export async function applyBackgroundBlurToLocal(lp: LocalParticipant): Promise<void> {
try {
const track = getCameraTrack(lp);
if (!track) return;
const processor = await getProcessor();
// `setProcessor` is declared on LocalVideoTrack; cast because the
// processor type lives in a separate module we don't want to strongly
// couple to here.
await (track as unknown as {
setProcessor: (p: unknown) => Promise<void>;
}).setProcessor(processor);
} catch (err: unknown) {
console.warn('applyBackgroundBlur failed', err);
}
}
export async function removeBackgroundBlurFromLocal(lp: LocalParticipant): Promise<void> {
try {
const track = getCameraTrack(lp);
if (!track) return;
const setter = (track as unknown as {
setProcessor?: (p: unknown) => Promise<void>;
stopProcessor?: () => Promise<void>;
});
if (setter.stopProcessor) {
await setter.stopProcessor();
} else if (setter.setProcessor) {
await setter.setProcessor(null);
}
} catch (err: unknown) {
console.warn('removeBackgroundBlur failed', err);
}
}