Skip to content

feat: webrtc 145 upgrade#2133

Merged
santhoshvai merged 39 commits into
mainfrom
feat/ios-render-improve
Jun 11, 2026
Merged

feat: webrtc 145 upgrade#2133
santhoshvai merged 39 commits into
mainfrom
feat/ios-render-improve

Conversation

@santhoshvai

@santhoshvai santhoshvai commented Feb 19, 2026

Copy link
Copy Markdown
Member

Overview

  • Bump @stream-io/react-native-webrtc to 145.0.0 (depends on rn-webrtc#27).
  • iOS: engine-lifecycle–driven audio session reconfiguration for interruption recovery.
  • CallKit path: session ownership guard between callingx and StreamInCallManager.
  • Fixes blank video on iOS PiP (only seen after 145)

Test plan

  • Dogfood iOS: join call, verify remote video appears quickly.
  • Go to PiP on iOS verifiy it works
  • Interrupt with Phone call/ Facetime / Siri; verify audio resumes.
  • Ringing: answer via CallKit; verify audio + no session conflict when moving to in-call UI. Interrupt with Phone call/ Facetime. Siri only works without callkit.
  • Android: smoke call + noise cancellation.

Summary by CodeRabbit

  • New Features

    • Mic mute detection and new audio-interruption/mic-mute events.
    • Cross-module session ownership for safer CallKit/audio handoffs.
  • Bug Fixes

    • More reliable audio session and engine lifecycle handling.
    • Improved picture‑in‑picture rendering and robust video buffer conversion/resizing.
  • Chores

    • Bumped WebRTC-related dependency to 145.0.0-alpha.4.

@changeset-bot

changeset-bot Bot commented Feb 19, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: aaa2f3d

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

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR bumps @stream-io/react-native-webrtc to 145.0.0-alpha.4, refactors iOS audio/session wiring to a shared instance and cross-package ownership flag, adds mic-mute/interruption events and engine lifecycle subscriptions, and improves Picture-in-Picture buffer handling and renderer content-state.

Changes

WebRTC Alpha & iOS Audio Refactor

Layer / File(s) Summary
Dependencies and configuration
sample-apps/react-native/dogfood/package.json, packages/noise-cancellation-react-native/android/build.gradle, packages/noise-cancellation-react-native/package.json, packages/react-native-callingx/package.json, packages/react-native-sdk/package.json
@stream-io/react-native-webrtc updated to 145.0.0-alpha.4 across packages; Android noise-cancellation artifact switched to stream-video-android-noise-cancellation-libwebrtc:3.0.0.
AudioSessionManager shared-instance refactor
packages/react-native-callingx/ios/AudioSessionManager.swift
AudioSessionManager converted from static utility to shared-instance with instance-owned state and audio queues; activation-cycle reapply guard removed; APIs changed to instance methods.
iOS audio ownership and interruption handling
packages/react-native-callingx/ios/CallingxSessionOwnership.swift, packages/react-native-callingx/ios/CallingxImpl.swift, packages/react-native-callingx/ios/Callingx.mm, packages/react-native-callingx/src/types.ts
Add CallingxSessionOwnership KVC-accessible flag; CallingxImpl now conforms to RTCAudioSessionDelegate, registers/unregisters route/interruption observers, emits didChangeMicMuteState and didEndAudioInterruption events, wires engine subscription, and updates CallKit ownership handling; TypeScript event types extended.
StreamInCallManager engine lifecycle subscription
packages/react-native-sdk/ios/StreamInCallManager.swift
Switch StreamInCallManager to Combine-based ADM engine lifecycle subscription, centralize audio configuration builder, gate enable/disable application by Callingx ownership, add interruption observer and debug logging.
PictureInPicture rendering and buffer improvements
packages/react-native-sdk/ios/PictureInPicture/StreamBufferTransformer.swift, packages/react-native-sdk/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift, packages/react-native-sdk/ios/PictureInPicture/StreamRTCYUVBuffer.swift
Normalize unknown RTC frame buffers to I420, round resize targets to even dimensions, add explicit dequeue error handling, unify renderer content-state, tighten frame gating, and refine overlay/avatar layout behavior.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • GetStream/stream-video-js#2251: Refactors AudioSessionManager from static to AudioSessionManager.shared and updates CallingxImpl integration; overlaps on audio-route/default-device wiring.

Suggested reviewers

  • oliverlaz
  • greenfrvr

Poem

"🐰 I hopped through code to bump WebRTC's seed,

Shared the session so audio's freed,
Ownership flags in tidy rows,
PiP frames even where YUV flows,
Interruptions logged — a happy deed!"

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description covers key aspects (dependency bump, iOS audio improvements, CallKit ownership guard, PiP fix) and includes a test plan, but lacks required template sections (Implementation notes, Ticket link, Docs link). Add missing template sections: 'Implementation notes' explaining the technical approach, a 'Ticket' link to the Linear issue, and optionally a 'Docs' link if documentation was updated.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: webrtc 145 upgrade' directly and accurately summarizes the main change: upgrading the WebRTC dependency to version 145 across multiple packages.
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 feat/ios-render-improve

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.

@santhoshvai santhoshvai marked this pull request as draft February 19, 2026 09:25

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@sample-apps/react-native/dogfood/ios/Podfile`:
- Line 13: Move the pod declaration for StreamWebRTC into the target block to
make the Podfile intent explicit: locate the top-level line "pod 'StreamWebRTC',
podspec:
'https://raw.githubusercontent.com/GetStream/stream-video-swift-webrtc/137.0.62/StreamWebRTC.podspec'"
and cut it into the "target 'StreamReactNativeVideoSDKSample'" block (near the
"use_frameworks! :linkage => :static" statement) so the pod is declared inside
that target rather than at root scope.

In `@sample-apps/react-native/dogfood/package.json`:
- Line 24: The PR updates the react-native WebRTC dependency to the pre-release
"@stream-io/react-native-webrtc": "137.1.3-alpha.1" but does not include the
regenerated CocoaPods lock; run pod install in the iOS workspace to produce an
updated Podfile.lock that reflects the pinned StreamWebRTC (e.g., the manual pin
"StreamWebRTC 137.0.62" in the Podfile), then add and commit the updated
Podfile.lock alongside the package.json change so other contributors will get
the exact CocoaPods resolution.

Comment thread sample-apps/react-native/dogfood/ios/Podfile Outdated
Comment thread sample-apps/react-native/dogfood/package.json Outdated
@santhoshvai santhoshvai changed the title feat(ios): improved frame rendering feat: webrtc 145 upgrade May 27, 2026
Comment thread packages/react-native-callingx/ios/AudioSessionManager.swift Outdated
oliverlaz and others added 13 commits June 2, 2026 10:36
### 💡 Overview

Adds `hasInterruptedTrack(participant, trackType)` to
`@stream-io/video-client` that returns `true` only when a track is in
both `interruptedTracks` and `publishedTracks`. This avoids a stale
"audio interrupted" indicator that lingers after a remote sender
unpublishes the track while it was interrupted, because the
receiver-side `unmute` event does not always fire for an unpublish.

📑 Docs: GetStream/docs-content#1322
…and Expo 56 (#2268)

Rolls up the dependency upgrades on the `deps-upgrade` branch into a single PR. This is a maintenance/chore change with no intended public API changes for the SDKs; the bulk of the diff is `yarn.lock`, sample-app manifests, and native lockfiles (`Podfile.lock`, `Gemfile.lock`, gradle wrapper).

Highlights:

- React Native 0.81 -> 0.85, React 19.1 -> 19.2
- Vite 8 and Vitest 4 (with test adaptations for Vitest 4 breaking changes)
- Expo SDK 56 patch releases (expo, expo-build-properties, expo-constants, expo-dev-client, expo-linking, expo-notifications, expo-router)
- @gorhom/bottom-sheet 5.1.8 -> 5.2.9 (dogfood)
- react-native-teleport 0.5.6 -> 1.1.7 (dogfood)
- React web sample apps dependency bumps

### 📝 Implementation notes

- `@gorhom/bottom-sheet` 5.2 removed `shouldHandleKeyboardEvents` from its internal context; the dogfood livestream chat (`BottomSheetChatWrapper.tsx`) was migrated to the new `animatedKeyboardState` / `textInputNodesRef` keyboard API.
- Vitest 4 test adaptations in `packages/client`.

---------

Co-authored-by: Ivan Sekovanikj <ivan.sekovanikj@getstream.io>
# Conflicts:
#	packages/noise-cancellation-react-native/package.json
#	packages/react-native-callingx/package.json
#	packages/video-filters-react-native/package.json
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	yarn.lock
# Conflicts:
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	sample-apps/react-native/dogfood/package.json
#	yarn.lock
# Conflicts:
#	packages/noise-cancellation-react-native/package.json
#	packages/react-native-callingx/package.json
#	packages/video-filters-react-native/package.json
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	sample-apps/react/react-dogfood/next-env.d.ts
#	yarn.lock
# Conflicts:
#	sample-apps/react-native/dogfood/ios/Podfile.lock
Decoded remote frames arrive as RTCNV12Buffer (enabled by the new NV12 rendering path), a type the PiP buffer transform didn't handle, so no CMSampleBuffer was produced and the PiP window stayed empty while the overlays still rendered.

  - Convert non-i420/non-CVPixelBuffer frames to i420 via toI420()
  - Round the resize target to even dimensions; odd YUV sizes break the
    pixel buffer pool and conversion
  - Gate rendering on a non-zero contentSize and recompute resize params
    in layoutSubviews once the real size is known
@santhoshvai santhoshvai marked this pull request as ready for review June 4, 2026 13:05
Comment thread .yarnrc.yml Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/noise-cancellation-react-native/android/build.gradle`:
- Line 110: The repository content filters currently whitelist only the module
'stream-video-android-noise-cancellation' so the new dependency
io.getstream:stream-video-android-noise-cancellation-libwebrtc:3.0.0 will be
blocked; update both snapshot repository content { ... includeModule(...) }
blocks to also include the module
'stream-video-android-noise-cancellation-libwebrtc' for group 'io.getstream'
(i.e., add includeModule("io.getstream",
"stream-video-android-noise-cancellation-libwebrtc") alongside the existing
includeModule calls) so the libwebrtc artifact can be resolved.
🪄 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: 5ffc788e-bbae-46ae-930e-04dc291221bd

📥 Commits

Reviewing files that changed from the base of the PR and between e4f0fd0 and 2a149f3.

📒 Files selected for processing (14)
  • .yarnrc.yml
  • packages/noise-cancellation-react-native/android/build.gradle
  • packages/noise-cancellation-react-native/package.json
  • packages/react-native-callingx/ios/AudioSessionManager.swift
  • packages/react-native-callingx/ios/Callingx.mm
  • packages/react-native-callingx/ios/CallingxImpl.swift
  • packages/react-native-callingx/ios/CallingxSessionOwnership.swift
  • packages/react-native-callingx/package.json
  • packages/react-native-callingx/src/types.ts
  • packages/react-native-sdk/ios/PictureInPicture/StreamBufferTransformer.swift
  • packages/react-native-sdk/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift
  • packages/react-native-sdk/ios/PictureInPicture/StreamRTCYUVBuffer.swift
  • packages/react-native-sdk/ios/StreamInCallManager.swift
  • packages/react-native-sdk/package.json
💤 Files with no reviewable changes (11)
  • packages/react-native-callingx/package.json
  • packages/react-native-callingx/ios/Callingx.mm
  • packages/react-native-callingx/ios/CallingxSessionOwnership.swift
  • packages/react-native-sdk/package.json
  • packages/react-native-callingx/src/types.ts
  • packages/react-native-callingx/ios/AudioSessionManager.swift
  • packages/react-native-sdk/ios/PictureInPicture/StreamBufferTransformer.swift
  • packages/react-native-sdk/ios/PictureInPicture/StreamRTCYUVBuffer.swift
  • packages/react-native-sdk/ios/StreamInCallManager.swift
  • packages/react-native-callingx/ios/CallingxImpl.swift
  • packages/react-native-sdk/ios/PictureInPicture/StreamPictureInPictureVideoRenderer.swift

Comment thread packages/noise-cancellation-react-native/android/build.gradle

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/noise-cancellation-react-native/android/build.gradle (1)

76-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix repository filters to match the new libwebrtc artifact.

Line 76 passes a full coordinate as the module name (io.getstream:...), which does not match Gradle’s includeModule(group, module) contract, and Line 89 still whitelists the old module. This can block resolution from snapshot repos for stream-video-android-noise-cancellation-libwebrtc.

Proposed fix
             content {
                 // This efficiently tells Gradle to only look for this specific dependency in this repository
-                includeModule('io.getstream', 'io.getstream:stream-video-android-noise-cancellation-libwebrtc')
+                includeModule('io.getstream', 'stream-video-android-noise-cancellation-libwebrtc')
             }
...
             content {
                 // This efficiently tells Gradle to only look for this specific dependency here
-                includeModule('io.getstream', 'stream-video-android-noise-cancellation')
+                includeModule('io.getstream', 'stream-video-android-noise-cancellation-libwebrtc')
             }
#!/bin/bash
set -euo pipefail

f="packages/noise-cancellation-react-native/android/build.gradle"

echo "== includeModule entries =="
rg -n "includeModule\(" "$f"

echo
echo "== dependency artifact =="
rg -n "stream-video-android-noise-cancellation" "$f"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/noise-cancellation-react-native/android/build.gradle` around lines
76 - 90, The repository filters are using the wrong module names: replace the
incorrect full-coordinate call includeModule('io.getstream',
'io.getstream:stream-video-android-noise-cancellation-libwebrtc') with the
proper group+module form includeModule('io.getstream',
'stream-video-android-noise-cancellation-libwebrtc') where includeModule is
used, and update the whitelist entry inside rootProject.allprojects (currently
including 'stream-video-android-noise-cancellation') to the new artifact name
'stream-video-android-noise-cancellation-libwebrtc' so Gradle can resolve
snapshots from the Sonatype repo.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@packages/noise-cancellation-react-native/android/build.gradle`:
- Around line 76-90: The repository filters are using the wrong module names:
replace the incorrect full-coordinate call includeModule('io.getstream',
'io.getstream:stream-video-android-noise-cancellation-libwebrtc') with the
proper group+module form includeModule('io.getstream',
'stream-video-android-noise-cancellation-libwebrtc') where includeModule is
used, and update the whitelist entry inside rootProject.allprojects (currently
including 'stream-video-android-noise-cancellation') to the new artifact name
'stream-video-android-noise-cancellation-libwebrtc' so Gradle can resolve
snapshots from the Sonatype repo.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dd55055d-deac-41c2-878c-a15adf24b4a3

📥 Commits

Reviewing files that changed from the base of the PR and between 4053f64 and f9603a9.

📒 Files selected for processing (1)
  • packages/noise-cancellation-react-native/android/build.gradle

santhoshvai and others added 11 commits June 5, 2026 17:13
Add a CallId badge overlaid at the top of the active meeting and ringing call screens. It shows the current call ID and opens the share sheet on tap so the ID can be copied or sent. The badge only renders while the call is active, so it never covers the lobby, ringing, or PiP UI.

Also shorten randomId() to a 6-char ID so it is easier to type elsewhere.
Accepting an incoming CallKit call after the app was killed started the mic
muted (UI muted + no audio out) until manual unmute.

With the WebRTC ADM in .voiceProcessing mute mode, iOS 17+ unifies
voice-processing input mute with the system input mute and CallKit auto-adopts
it. So the app's transient setMutedCall(true) (synced while isMute is still
true pre-join) round-trips back as a system-initiated CXSetMutedCallAction, and
engine startup emits more. Forwarding those to JS ran microphone.disable() and
the mic stuck muted.

performSetMutedCallAction now forwards only genuine native-CallKit-UI mutes,
suppressing:
- app-initiated actions, matched by CXAction.uuid (appInitiatedMuteActionIds;
  a set, so concurrent toggles each match their own action)
- the iOS 17 system echo of our own setMutedCall, matched by value
  (lastAppRequestedMute), reset on call end so it can't leak across calls
- engine-startup artifacts, via an isAudioEngineStarting window
  (willEnableAudioEngine..willStartAudioEngine)

Also re-wire the ADM engine subscription when the ADM instance changes, so a JS
reload (new WebRTCModule) doesn't leave it bound to a dead publisher, and remove
the now-unused per-call isSelfMuted flag.

Replaces the package's #if DEBUG NSLog calls with CallingxLog, a unified
os.Logger wrapper (per-area categories under the io.getstream.callingx
subsystem, public-privacy values, @objc bridge for ObjC callers), so logs are
filterable via Console.app / `log stream` without an attached debugger.
Comment thread packages/react-native-sdk/package.json Outdated
@santhoshvai santhoshvai merged commit 07825e4 into main Jun 11, 2026
7 of 8 checks passed
@santhoshvai santhoshvai deleted the feat/ios-render-improve branch June 11, 2026 10:31
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.

3 participants