Skip to content

fix(rn): perf and stability fixes for video-filters#2216

Merged
santhoshvai merged 15 commits intomainfrom
filters-investigate
Apr 28, 2026
Merged

fix(rn): perf and stability fixes for video-filters#2216
santhoshvai merged 15 commits intomainfrom
filters-investigate

Conversation

@santhoshvai
Copy link
Copy Markdown
Member

@santhoshvai santhoshvai commented Apr 23, 2026

💡 Overview

Correctness, perf, and cleanup fixes in the React Native background-filter pipeline.

📝 Implementation notes

  • iOS: fix blur background-drift (CIGaussianBlur extent); run Vision segmentation at ~540p (2–4× faster on mid-tier chips); close retain cycle in filter closures and NotificationCenter observer leak.
  • iOS segmentation async: run Vision off the capture thread on a dedicated serial queue; composite using the last completed mask (≤1-frame staleness, imperceptible). Mirrors Android's ML Kit
    pattern. Unblocks the capture thread so preview stays at 30 fps on older chips (e.g. iPhone XS) where Vision was previously eating most of the frame budget.
  • Android: per-filter YuvFrame instance (fixes camera-flip race); GL/libyuv resource cleanup via a new VideoFrameProcessor.dispose() lifecycle hook.
  • Remote URL backgrounds: loaded off-thread on both platforms with timeouts; host-only error logging.
  • SDK provider: reapply on track replacement (camera flip); staleness guard for in-flight apply calls; unregisterAllFilters() on unmount so native processors can deallocate.

Requires the paired react-native-webrtc PR for the dispose() hook and a camera-flip regression fix.

🎫 Ticket: https://linear.app/stream/issue/XYZ-123

📑 Docs: https://github.com/GetStream/docs-content/pull/

Summary by CodeRabbit

  • New Features

    • Added an "unregister all filters" control to release previously registered filters.
  • Bug Fixes

    • Prevents stale/overlapping filter changes and reapplies effects when media tracks update.
    • Improved teardown to reliably remove filters and clear cached resources.
  • Performance Improvements

    • Background images load asynchronously to avoid UI blocking.
    • Blur processing downsamples for more efficient rendering.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 23, 2026

⚠️ No Changeset found

Latest commit: 14ecbfb

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

Warning

Rate limit exceeded

@santhoshvai has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 41 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 43d5dbad-42c9-469b-b6b2-f3bd0609389a

📥 Commits

Reviewing files that changed from the base of the PR and between da40beb and 14ecbfb.

⛔ Files ignored due to path filters (2)
  • sample-apps/react-native/dogfood/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (6)
  • packages/react-native-sdk/package.json
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt
  • packages/video-filters-react-native/package.json
  • sample-apps/react-native/dogfood/package.json
  • sample-apps/react-native/expo-video-sample/package.json
  • sample-apps/react-native/ringing-tutorial/package.json
📝 Walkthrough

Walkthrough

Adds async image/filter loading, explicit native unregistering, instance-based YUV converters with explicit disposal, reapplication of native filters when media tracks change, and multiple lifecycle/cleanup fixes across React Native, Android, and iOS components.

Changes

Cohort / File(s) Summary
React Native: background filter state & reapply
packages/react-native-sdk/src/contexts/BackgroundFilters.tsx
Tracks last-applied native filter name, guards against stale concurrent applies, subscribes to media stream track changes to reapply filters, and clears state on cleanup or disable.
React Native: native bridge API
packages/video-filters-react-native/src/index.ts
Adds unregisterAllFilters() JS export to forward unregistration to native.
Android: bridge, registration & lifecycle
packages/video-filters-react-native/android/src/main/java/.../VideoFiltersReactNativeModule.kt
Tracks registered processor names, adds unregisterAllFilters to remove them from Provider, and adjusts registration code to populate tracking.
iOS: bridge & tracking
packages/video-filters-react-native/ios/VideoFiltersReactNative.mm, packages/video-filters-react-native/ios/VideoFiltersReactNative.swift
Adds exported unregisterAllFilters, tracks registered processor names in Swift, and removes tracked processors on unregister.
Android: YUV handling & disposal
packages/video-filters-react-native/android/src/main/java/.../YuvFrame.kt, .../VideoFrameWithBitmapFilter.kt
Converts YuvFrame singleton → class with close(), uses instance conversion, and adds dispose() to free libyuv buffers, cached bitmaps, converters, texture, and related resources.
Android: virtual background async load
packages/video-filters-react-native/android/src/main/java/.../factories/VirtualBackgroundFactory.kt
Switches from lazy sync decode to async preload into a @Volatile bitmap (skips filtering until ready), centralizes remote timeout, and improves remote logging.
Android: Bitmap filter lifecycle
packages/video-filters-react-native/android/src/main/java/.../BitmapVideoFilter.kt, .../BackgroundBlurFactory.kt
Adds overridable close() on BitmapVideoFilter; background blur filter now closes ML Kit segmenter and recycles cached bitmaps.
iOS: image background async load & blur optimization
packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift, .../BlurBackgroundVideoFrameProcessor.swift
Replaces blocking image decode with async loading and thread-safe state; blur now downscales/clamps/crops then upscales to reduce work; closures capture self weakly and return original image until ready.
iOS: async segmentation & thread-safety
packages/video-filters-react-native/ios/VideoFrameProcessors/Utils/BackgroundImageFilterProcessor.swift
Reworks segmentation to use cached lastMask, run segmentation asynchronously on a serial queue with CIContext snapshots, protects state with a lock and inFlight flag, and avoids per-frame synchronous Vision runs.
iOS: notification cleanup
packages/video-filters-react-native/ios/VideoFrameProcessors/Utils/VideoFilters.swift
Adds deinit to unregister from NotificationCenter upon deallocation.
Package bumps (dev/sample)
packages/react-native-sdk/package.json, sample-apps/react-native/dogfood/package.json
Bumps @stream-io/react-native-webrtc to 137.2.0-alpha.5 in devDependencies and sample app.
JS native module: unregister API
packages/video-filters-react-native/src/index.ts
Exports unregisterAllFilters() to call native unregister.
iOS/Android: native module unregister implementations
packages/video-filters-react-native/ios/..., packages/video-filters-react-native/android/...
Adds native implementations to remove tracked processors and clear tracking state.
sequenceDiagram
  participant RN as React Native UI
  participant SDK as BackgroundFilters.tsx
  participant Native as VideoFiltersReactNative (JS bridge)
  participant Provider as ProcessorProvider / Native Filters
  participant Tracks as MediaStream / VideoTracks

  RN->>SDK: apply / disable filter
  SDK->>Native: registerFilter / unregisterFilter (sets lastAppliedFilterNameRef)
  Native->>Provider: add processor (store name in registeredNames)
  SDK->>Tracks: subscribe to track changes
  Tracks-->>SDK: tracks replaced
  SDK->>Native: reapply recorded filter name to new tracks
  RN->>SDK: call unregisterAllFilters
  SDK->>Native: unregisterAllFilters
  Native->>Provider: remove all processors in registeredNames (clear set)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰
I hop through frames where pixels bloom and fade,
I stash the names, unroll the filters’ braid,
Async crumbs I guard, old buffers tucked away,
I close the gaps, then bounce to greet the day,
Sniffing code, I twitch — the app looks gay.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(rn): perf and stability fixes for video-filters' accurately summarizes the main changes—performance and stability improvements across the React Native video-filters package, covering both iOS and Android layers.
Description check ✅ Passed The description includes all required sections (Overview and Implementation notes) with detailed technical context about correctness, performance, and cleanup fixes across platforms, dependencies, and lifecycle management.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch filters-investigate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/react-native-sdk/src/contexts/BackgroundFilters.tsx (1)

88-178: ⚠️ Potential issue | 🟠 Major

Guard async filter application against stale operations.

Each apply path awaits registration before setting lastAppliedFilterNameRef, applying the native effect, and updating state. If the user disables filters or selects another filter while registration is in flight, the older promise can resolve later and re-apply a stale filter.

Suggested change
   const isVideoBlurRegisteredRef = useRef(false);
   const registeredImageFiltersSetRef = useRef(new Set<string>());
+  const filterOperationIdRef = useRef(0);
@@
   const applyBackgroundBlurFilter = useCallback(
     async (blurIntensity: BlurIntensity) => {
+      const operationId = ++filterOperationIdRef.current;
       if (!isSupported) {
         return;
       }
       if (!isBackgroundBlurRegisteredRef.current) {
         await videoFiltersModule?.registerBackgroundBlurVideoFilters();
+        if (operationId !== filterOperationIdRef.current) return;
         isBackgroundBlurRegisteredRef.current = true;
       }
@@
   const applyVideoBlurFilter = useCallback(
     async (blurIntensity: BlurIntensity) => {
+      const operationId = ++filterOperationIdRef.current;
       if (!isSupported) {
         return;
       }
       if (!isVideoBlurRegisteredRef.current) {
         await videoFiltersModule?.registerBlurVideoFilters();
+        if (operationId !== filterOperationIdRef.current) return;
         isVideoBlurRegisteredRef.current = true;
       }
@@
   const applyBackgroundImageFilter = useCallback(
     async (imageSource: ImageSourceType) => {
+      const operationId = ++filterOperationIdRef.current;
       if (!isSupported) {
         return;
       }
@@
       if (!registeredImageFiltersSet.has(imageUri)) {
         await videoFiltersModule?.registerVirtualBackgroundFilter(imageSource);
+        if (operationId !== filterOperationIdRef.current) return;
         registeredImageFiltersSetRef.current.add(imageUri);
       }
@@
   const disableAllFilters = useCallback(() => {
+    filterOperationIdRef.current += 1;
     if (!isSupported) {
       return;
     }

As per coding guidelines, **/*.{ts,tsx}: Use AbortController to cancel network requests and media operations on component unmount; check instance IDs and timestamps before state updates to avoid race conditions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-native-sdk/src/contexts/BackgroundFilters.tsx` around lines 88
- 178, The async apply functions (applyBackgroundBlurFilter,
applyVideoBlurFilter, applyBackgroundImageFilter) can finish after the user has
changed/disabled filters and thus re-apply stale effects; fix this by
introducing an operation token (e.g., opCounterRef or AbortController) that you
capture at the start of each apply* call, increment when disableAllFilters or a
new apply starts, and then after any await (registration or image resolution)
verify the token still matches before setting lastAppliedFilterNameRef, calling
track._setVideoEffect, or calling setCurrentBackgroundFilter; also update
disableAllFilters to bump/invalidate the token so in-flight operations abort
applying their results.
packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt (1)

12-17: ⚠️ Potential issue | 🟠 Major

Add explicit buffer cleanup to YuvFrame since it now holds per-instance resources.

The libYuvRotatedI420Buffer and libYuvAbgrBuffer are only released when frame dimensions change (lines 66, 73, 84), not when the processor is destroyed. Since YuvFrame is now instantiated per-processor in VideoFrameProcessorWithBitmapFilter (line 21), these buffers leak whenever a processor is torn down without processing frames of different dimensions.

Suggested direction
 class YuvFrame {
@@
   private fun createLibYuvAbgrBuffer() {
@@
     libYuvRotatedI420Buffer!!.convertTo(libYuvAbgrBuffer!!)
   }
+
+  fun close() {
+    libYuvRotatedI420Buffer?.close()
+    libYuvRotatedI420Buffer = null
+    libYuvAbgrBuffer?.close()
+    libYuvAbgrBuffer = null
+  }

Then call yuvFrame.close() from the processor/filter teardown if the external VideoFrameProcessor interface provides a lifecycle hook. Confirm availability with the WebRTC module dependency.

Also applies to: 65-88

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt`
around lines 12 - 17, YuvFrame holds per-instance native buffers
(libYuvRotatedI420Buffer, libYuvAbgrBuffer) that are only released on dimension
change; add an explicit cleanup method (e.g., fun close() or release()) on
YuvFrame that releases and nulls libYuvRotatedI420Buffer and libYuvAbgrBuffer
(and any other held native resources) to avoid leaks, and call that method from
the processor/filter teardown in VideoFrameProcessorWithBitmapFilter (or
wherever the processor is destroyed); reference the existing buffer fields
(libYuvRotatedI420Buffer, libYuvAbgrBuffer) and the YuvFrame class so reviewers
can locate and wire up the lifecycle hook.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react-native-sdk/src/contexts/BackgroundFilters.tsx`:
- Around line 181-207: Replace the manual RxJS subscription in the effect with
the React hook that exposes camera state: call
useCallStateHooks()/useCameraState() to get const { mediaStream } =
useCameraState() and use mediaStream directly inside the effect instead of
subscribing to call.camera.state.mediaStream$; update the effect dependencies to
include mediaStream (e.g. [call, mediaStream]), remove subscription
creation/unsubscription, and keep the same logic that iterates
mediaStream?.getVideoTracks() calling track._setVideoEffect(name) on mount and
track._setVideoEffect(null) in the cleanup while still resetting
lastAppliedFilterNameRef.current, isBackgroundBlurRegisteredRef.current,
isVideoBlurRegisteredRef.current, and clearing
registeredImageFiltersSetRef.current so the behavior around
lastAppliedFilterNameRef, registeredImageFiltersSetRef,
isBackgroundBlurRegisteredRef and isVideoBlurRegisteredRef remains unchanged.

In
`@packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt`:
- Around line 73-86: In loadBackgroundImage within VirtualBackgroundFactory,
replace the direct URLConnection + openInputStream call with a URLConnection
where you set connect and read timeouts (e.g., setConnectTimeout,
setReadTimeout), obtain the InputStream and decode it inside a
try-with-resources style block (Kotlin .use { ... }) so the stream is always
closed, and change the error log that currently includes
backgroundImageUrlString to avoid printing the raw URL (log a masked value,
hostname only, or a constant like "[REDACTED]" alongside the exception); update
BitmapFactory.decodeStream usage accordingly to use the closed-safe stream.

In
`@packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift`:
- Around line 83-86: The failure branch that currently logs the full
backgroundImageUrl (inside the Data(contentsOf: url) handling where bgUIImage is
set) can leak sensitive tokens; change the log to avoid printing the full URL
and instead log a non-sensitive identifier such as the URL host or filename, or
a sanitized/hashed representation, or simply log "Failed to convert background
image URI" along with the error/URL length or last N characters, ensuring you
reference backgroundImageUrl only in a redacted form; update the NSLog call in
ImageBackgroundVideoFrameProcessor.swift where bgUIImage is set to reflect this.

---

Outside diff comments:
In `@packages/react-native-sdk/src/contexts/BackgroundFilters.tsx`:
- Around line 88-178: The async apply functions (applyBackgroundBlurFilter,
applyVideoBlurFilter, applyBackgroundImageFilter) can finish after the user has
changed/disabled filters and thus re-apply stale effects; fix this by
introducing an operation token (e.g., opCounterRef or AbortController) that you
capture at the start of each apply* call, increment when disableAllFilters or a
new apply starts, and then after any await (registration or image resolution)
verify the token still matches before setting lastAppliedFilterNameRef, calling
track._setVideoEffect, or calling setCurrentBackgroundFilter; also update
disableAllFilters to bump/invalidate the token so in-flight operations abort
applying their results.

In
`@packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt`:
- Around line 12-17: YuvFrame holds per-instance native buffers
(libYuvRotatedI420Buffer, libYuvAbgrBuffer) that are only released on dimension
change; add an explicit cleanup method (e.g., fun close() or release()) on
YuvFrame that releases and nulls libYuvRotatedI420Buffer and libYuvAbgrBuffer
(and any other held native resources) to avoid leaks, and call that method from
the processor/filter teardown in VideoFrameProcessorWithBitmapFilter (or
wherever the processor is destroyed); reference the existing buffer fields
(libYuvRotatedI420Buffer, libYuvAbgrBuffer) and the YuvFrame class so reviewers
can locate and wire up the lifecycle hook.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6b52b4a-ca8d-446f-a851-1a40b1972485

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc02b9 and 06990a0.

📒 Files selected for processing (7)
  • packages/react-native-sdk/src/contexts/BackgroundFilters.tsx
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/VideoFrameWithBitmapFilter.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt
  • packages/video-filters-react-native/ios/VideoFrameProcessors/BlurBackgroundVideoFrameProcessor.swift
  • packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift
  • packages/video-filters-react-native/ios/VideoFrameProcessors/Utils/VideoFilters.swift

Comment thread packages/react-native-sdk/src/contexts/BackgroundFilters.tsx Outdated
@santhoshvai santhoshvai marked this pull request as draft April 24, 2026 07:59
@santhoshvai santhoshvai marked this pull request as ready for review April 28, 2026 09:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/VideoFiltersReactNativeModule.kt`:
- Around line 13-15: The current cleanup unconditionally removes names in the
instance-scoped registeredNames from the global ProcessorProvider in
unregisterAllFilters(), which can unregister processors still used by other
owners; change this to scope cleanup to the owner by implementing an owner token
or reference-counted registry: replace direct use of the global
ProcessorProvider removal with a per-owner token (or increment/decrement a
ref-count map keyed by processor name) so that unregisterAllFilters() only
decrements/refcounts and removes a processor from ProcessorProvider when its
count reaches zero; update references to registeredNames,
unregisterAllFilters(), and any global ProcessorProvider.remove/unregister calls
to use the new token/ref-count logic.

In `@packages/video-filters-react-native/ios/VideoFiltersReactNative.swift`:
- Around line 4-6: registeredNames is a global Set<String> used by
BackgroundFiltersProvider and leads to unsafe blanket cleanup via
unregisterAllFilters(); change to per-owner tracking: associate registrations
with an owner token (e.g., a UUID) when calling registerProcessor/registerFilter
so BackgroundFiltersProvider creates a unique ownerId on init and uses it on
cleanup; replace the single registeredNames with a dictionary Map<String,
Set<String>> or [ownerId: Set<processorName>] and update register/unregister
functions (references: registeredNames, BackgroundFiltersProvider,
unregisterAllFilters, registerProcessor) to add/remove only the names tied to
that ownerId, and ensure unregisterAllFilters accepts an ownerId to only remove
that owner's processors.

In
`@packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift`:
- Around line 74-85: The current loadBackgroundImage function uses
Data(contentsOf:) which can block; replace the synchronous loader with an async
URLSession dataTask created from a URLRequest that sets timeoutInterval, assign
the returned URLSessionDataTask to a property (e.g., backgroundImageTask) so it
can be cancelled, and on success convert the received Data into a UIImage
exactly where bgUIImage is set today; also update the processor cleanup/teardown
(where ImageBackgroundVideoFrameProcessor is cleaned up) to call
backgroundImageTask?.cancel() to prevent stale network activity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 25b65f89-7e46-47e7-9589-04fd04a76dcb

📥 Commits

Reviewing files that changed from the base of the PR and between 06990a0 and 0c79f8f.

⛔ Files ignored due to path filters (2)
  • sample-apps/react-native/dogfood/ios/Podfile.lock is excluded by !**/*.lock
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • packages/react-native-sdk/package.json
  • packages/react-native-sdk/src/contexts/BackgroundFilters.tsx
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/VideoFiltersReactNativeModule.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/VideoFrameWithBitmapFilter.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt
  • packages/video-filters-react-native/ios/VideoFiltersReactNative.mm
  • packages/video-filters-react-native/ios/VideoFiltersReactNative.swift
  • packages/video-filters-react-native/ios/VideoFrameProcessors/BlurBackgroundVideoFrameProcessor.swift
  • packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift
  • packages/video-filters-react-native/ios/VideoFrameProcessors/Utils/BackgroundImageFilterProcessor.swift
  • packages/video-filters-react-native/src/index.ts
  • sample-apps/react-native/dogfood/package.json
✅ Files skipped from review due to trivial changes (2)
  • sample-apps/react-native/dogfood/package.json
  • packages/react-native-sdk/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/VideoFrameWithBitmapFilter.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/YuvFrame.kt
  • packages/react-native-sdk/src/contexts/BackgroundFilters.tsx

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react-native-sdk/src/contexts/BackgroundFilters.tsx`:
- Around line 80-83: Replace the stale-apply detection that only checks
lastAppliedFilterNameRef with a monotonic request token: add a requestIdRef
(number) that you increment for every new apply call, capture the current
requestId in the async apply (e.g., inside applyBackgroundBlurFilter /
applyBackgroundReplacement / related applyX functions), and before any mutation
of is*RegisteredRef or setState verify the captured requestId still equals
requestIdRef.current; also store the requestId alongside
lastAppliedFilterNameRef (e.g., {name, id}) so older promises that happen to
request the same name cannot win; apply the same pattern where name-only checks
occur (around the other occurrences noted) to prevent race conditions.

In
`@packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt`:
- Around line 69-95: The async image decode started in init (Thread {
loadBackgroundImage() }.start()) can complete after close() and repopulate
virtualBackgroundBitmap, so add a thread-safe cancellation check: introduce a
volatile/AtomicBoolean flag (e.g., isClosed or cancelled) set to true in
close(), and in loadBackgroundImage() check this flag both before assigning
virtualBackgroundBitmap and immediately after decoding the Bitmap (before any
assignment) to avoid writing the late result; ensure access to
virtualBackgroundBitmap is synchronized/atomic where needed so the check and
assignment are race-free and skip/recycle the decoded bitmap when cancelled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f486323e-ffce-4a6e-83ae-bc0250080b04

📥 Commits

Reviewing files that changed from the base of the PR and between 0c79f8f and da40beb.

📒 Files selected for processing (6)
  • packages/react-native-sdk/src/contexts/BackgroundFilters.tsx
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/BitmapVideoFilter.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/VideoFrameWithBitmapFilter.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/BackgroundBlurFactory.kt
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/factories/VirtualBackgroundFactory.kt
  • packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift
✅ Files skipped from review due to trivial changes (1)
  • packages/video-filters-react-native/android/src/main/java/com/streamio/videofiltersreactnative/common/BitmapVideoFilter.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/video-filters-react-native/ios/VideoFrameProcessors/ImageBackgroundVideoFrameProcessor.swift

Comment thread packages/react-native-sdk/src/contexts/BackgroundFilters.tsx
@santhoshvai santhoshvai merged commit db1405b into main Apr 28, 2026
10 of 11 checks passed
@santhoshvai santhoshvai deleted the filters-investigate branch April 28, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant