From ebfc72c735af85a7991cf0436f31117a819bd0de Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 13 Feb 2026 14:13:52 +0100 Subject: [PATCH 1/4] Export isFrameProcessor helper --- packages/livekit-rtc/src/frame_processor.ts | 36 +++++++-------------- packages/livekit-rtc/src/index.ts | 1 + 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/packages/livekit-rtc/src/frame_processor.ts b/packages/livekit-rtc/src/frame_processor.ts index d8f4b2f9..78466134 100644 --- a/packages/livekit-rtc/src/frame_processor.ts +++ b/packages/livekit-rtc/src/frame_processor.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 -import { type AudioFrame } from './audio_frame.js'; +import { AudioFrame } from './audio_frame.js'; import { type VideoFrame } from './video_frame.js'; export type FrameProcessorStreamInfo = { @@ -17,40 +17,26 @@ export type FrameProcessorCredentials = { export const FrameProcessorSymbol = Symbol.for('lk.frame-processor'); -export function isFrameProcessor( +export function isFrameProcessor< + T extends FrameProcessor | FrameProcessor | unknown, +>( maybeProcessor: unknown, - type?: Type, -): maybeProcessor is FrameProcessor< - Type extends 'audio' ? AudioFrame : Type extends 'video' ? VideoFrame : AudioFrame | VideoFrame -> { +): maybeProcessor is T extends FrameProcessor + ? FrameProcessor + : T extends FrameProcessor + ? FrameProcessor + : FrameProcessor | FrameProcessor { return ( maybeProcessor !== null && typeof maybeProcessor === 'object' && 'symbol' in maybeProcessor && - maybeProcessor.symbol === FrameProcessorSymbol && - (!type || ('type' in maybeProcessor && maybeProcessor.type === type)) + maybeProcessor.symbol === FrameProcessorSymbol ); } -export function isAudioFrameProcessor( - maybeProcessor: unknown, -): maybeProcessor is FrameProcessor { - return isFrameProcessor(maybeProcessor, 'audio'); -} - -export function isVideoFrameProcessor( - maybeProcessor: unknown, -): maybeProcessor is FrameProcessor { - return isFrameProcessor(maybeProcessor, 'video'); -} - export abstract class FrameProcessor { readonly symbol = FrameProcessorSymbol; - abstract readonly type: Frame extends VideoFrame - ? 'video' - : Frame extends AudioFrame - ? 'audio' - : never; + abstract isEnabled(): boolean; abstract setEnabled(enabled: boolean): void; diff --git a/packages/livekit-rtc/src/index.ts b/packages/livekit-rtc/src/index.ts index d60dc5a7..add4999d 100644 --- a/packages/livekit-rtc/src/index.ts +++ b/packages/livekit-rtc/src/index.ts @@ -54,4 +54,5 @@ export { FrameProcessor, type FrameProcessorStreamInfo, type FrameProcessorCredentials, + isFrameProcessor, } from './frame_processor.js'; From d26732c3f5e66b0e48519fa76ea810125cf7a525 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 13 Feb 2026 14:15:40 +0100 Subject: [PATCH 2/4] patch only --- .changeset/eleven-timers-kick.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eleven-timers-kick.md b/.changeset/eleven-timers-kick.md index a84a957f..8aa5ef38 100644 --- a/.changeset/eleven-timers-kick.md +++ b/.changeset/eleven-timers-kick.md @@ -1,5 +1,5 @@ --- -"@livekit/rtc-node": minor +"@livekit/rtc-node": patch --- Add typeguards for frame processors in order to avoid dual package hazard From 5735f32e151782c18c793170440ebb921e576af3 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 13 Feb 2026 14:16:51 +0100 Subject: [PATCH 3/4] import only type --- packages/livekit-rtc/src/frame_processor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/livekit-rtc/src/frame_processor.ts b/packages/livekit-rtc/src/frame_processor.ts index 78466134..629d883a 100644 --- a/packages/livekit-rtc/src/frame_processor.ts +++ b/packages/livekit-rtc/src/frame_processor.ts @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2025 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 -import { AudioFrame } from './audio_frame.js'; +import { type AudioFrame } from './audio_frame.js'; import { type VideoFrame } from './video_frame.js'; export type FrameProcessorStreamInfo = { From 4ad9892f850588b0f566a5646bfe0a682279a636 Mon Sep 17 00:00:00 2001 From: lukasIO Date: Fri, 13 Feb 2026 15:14:22 +0100 Subject: [PATCH 4/4] fix build --- packages/livekit-rtc/src/audio_stream.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/livekit-rtc/src/audio_stream.ts b/packages/livekit-rtc/src/audio_stream.ts index 94181cb1..b98ed853 100644 --- a/packages/livekit-rtc/src/audio_stream.ts +++ b/packages/livekit-rtc/src/audio_stream.ts @@ -5,7 +5,7 @@ import type { UnderlyingSource } from 'node:stream/web'; import { AudioFrame } from './audio_frame.js'; import type { FfiEvent } from './ffi_client.js'; import { FfiClient, FfiClientEvent, FfiHandle } from './ffi_client.js'; -import { type FrameProcessor, isAudioFrameProcessor } from './frame_processor.js'; +import { type FrameProcessor, isFrameProcessor } from './frame_processor.js'; import { log } from './log.js'; import type { NewAudioStreamResponse } from './proto/audio_frame_pb.js'; import { AudioStreamType, NewAudioStreamRequest } from './proto/audio_frame_pb.js'; @@ -41,7 +41,7 @@ class AudioStreamSource implements UnderlyingSource { if (sampleRateOrOptions !== undefined && typeof sampleRateOrOptions !== 'number') { this.sampleRate = sampleRateOrOptions.sampleRate ?? 48000; this.numChannels = sampleRateOrOptions.numChannels ?? 1; - if (isAudioFrameProcessor(sampleRateOrOptions.noiseCancellation)) { + if (isFrameProcessor(sampleRateOrOptions.noiseCancellation)) { this.frameProcessor = sampleRateOrOptions.noiseCancellation; } else { this.legacyNcOptions = sampleRateOrOptions.noiseCancellation;