Skip to content

feat: added audio capture for ios broadcast screensharing mode - #2346

Merged
greenfrvr merged 8 commits into
mainfrom
feat/ios-broadcast-screenshare-audio
Aug 4, 2026
Merged

feat: added audio capture for ios broadcast screensharing mode#2346
greenfrvr merged 8 commits into
mainfrom
feat/ios-broadcast-screenshare-audio

Conversation

@greenfrvr

@greenfrvr greenfrvr commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

💡 Overview

Added audio capturing for iOS broadcast screen sharing type.
Added .mixWithOthers default option to all audio session configurations, which prevents audio engine from stopping when other apps start audio session with different configuration.
Changed default screen sharing type in dogfood app.

📝 Implementation notes

Added AudioUploader which works similar to SampleUploader: it sends bytes data via socket connection. Server is started on webrtc side. Bytes chunks are accumulated and pushed to ring buffer as they are ready. Audio mixing part stays as is (as it was for in-app audio capturing).

🎫 Ticket: https://linear.app/stream/issue/RN-416/ios-broadcast-screen-sharing-audio-capturing

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

Corresponding WebRTC PR: GetStream/react-native-webrtc#58

Summary by CodeRabbit

  • New Features
    • Added audio streaming for iOS broadcast screen sharing.
    • Video and broadcast audio now use separate connections.
    • Broadcast audio is streamed to the app and mixed into the screen-share audio track, including a fallback capture path.
    • Added bounded retry handling for broadcast audio connections.
  • Improvements
    • Audio sessions can now mix with other audio sources.
  • Documentation
    • Updated guidance for the iOS includeAudio option.
  • Sample App
    • Enabled broadcast screen sharing with audio.

@greenfrvr greenfrvr self-assigned this Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 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

iOS broadcast capture now streams app audio through a dedicated socket, routes video and audio independently, and supports fallback screen-share audio mixing. The Expo plugin and Xcode project include the audio uploader, and audio session configurations enable mixing with other audio.

Changes

iOS broadcast audio

Layer / File(s) Summary
Audio frame serialization and streaming
packages/react-native-sdk/expo-config-plugin/static/AudioUploader.swift, sample-apps/react-native/dogfood/ios/Broadcast Extension/AudioUploader.swift
Adds PCM validation, planar-to-interleaved conversion, endian handling, 24-byte framing, readiness tracking, and chunked socket writes.
Broadcast audio and video routing
packages/react-native-sdk/expo-config-plugin/src/withIosScreenCapture/withTarget.ts, packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift, sample-apps/react-native/dogfood/ios/Broadcast Extension/SampleHandler.swift, sample-apps/react-native/dogfood/ios/StreamReactNativeVideoSDKSample.xcodeproj/project.pbxproj
Installs and registers AudioUploader.swift, creates separate video/audio connections, routes video and app-audio samples, bounds audio connection retries, and adds the uploader to the Xcode target.
Screen-share audio mixing fallback
packages/react-native-sdk/ios/StreamVideoReactNative.m
Starts ScreenAudioCapture when needed, forwards PCM buffers to the mixer, and stops and detaches the fallback during cleanup.
Broadcast audio configuration
sample-apps/react-native/dogfood/src/components/CallControls/BottomControls/index.tsx, packages/react-native-sdk/src/hooks/useScreenShareButton.ts
Selects broadcast screen sharing with audio enabled and updates the related option documentation.
Audio session mixing options
packages/react-native-callingx/ios/AudioSessionManager.swift, packages/react-native-sdk/ios/StreamInCallManager.swift
Adds .mixWithOthers to playback, recording, communicator, speaker, and earpiece audio session configurations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScreenShareToggleButton
  participant SampleHandler
  participant AudioUploader
  participant SocketConnection
  participant ScreenAudioCapture
  participant ScreenShareAudioMixer
  ScreenShareToggleButton->>SampleHandler: start broadcast with audio
  SampleHandler->>SocketConnection: open audio connection
  SampleHandler->>AudioUploader: send app-audio sample
  AudioUploader->>SocketConnection: write framed PCM chunks
  ScreenAudioCapture->>ScreenShareAudioMixer: forward fallback PCM buffers
Loading

Suggested reviewers: oliverlaz

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title accurately describes the main change: adding audio capture for iOS broadcast screen sharing mode.
Description check ✅ Passed The description provides a clear overview, implementation notes, ticket link, and documentation link as required by the template.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ios-broadcast-screenshare-audio

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.

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bundle size

Built package output. Sizes in KB; delta vs main@eedc526.

No significant package size increase vs main.

@greenfrvr
greenfrvr marked this pull request as ready for review July 29, 2026 10:14

@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: 3

🧹 Nitpick comments (2)
packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift (1)

134-151: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Connect-retry timers are unreachable after creation in both SampleHandler copies. The DispatchSourceTimer is only captured by its own event handler, so broadcastFinished cannot cancel it and the audio retry loop keeps firing for up to ~30s past teardown; openVideoConnection has the same shape.

  • packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift#L134-L151: store the timers as properties, cancel them in broadcastFinished, and extract one shared open-with-retry helper.
  • sample-apps/react-native/dogfood/ios/Broadcast Extension/SampleHandler.swift#L134-L151: mirror the change to keep the dogfood extension aligned with the template.
🤖 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/react-native-sdk/expo-config-plugin/static/SampleHandler.swift`
around lines 134 - 151, Update SampleHandler.swift at
packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift:134-151
and sample-apps/react-native/dogfood/ios/Broadcast
Extension/SampleHandler.swift:134-151 to store audio and video retry timers as
properties, extract their shared retry logic into one open-with-retry helper,
and cancel both timers from broadcastFinished so no retry continues after
teardown.
packages/react-native-sdk/expo-config-plugin/src/withIosScreenCapture/withTarget.ts (1)

182-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add unit-test coverage for the new AudioUploader.swift source entry.

The modified source registers AudioUploader.swift alongside SampleUploader.swift, but the plugin tests do not cover withTarget.ts or the Xcode build-phase expectations for these static Swift sources. Add a test/snapshot so future diffing catches regressions in the modifier’s file-copy and addSourceFile expectations.

🤖 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/react-native-sdk/expo-config-plugin/src/withIosScreenCapture/withTarget.ts`
around lines 182 - 189, Add unit-test or snapshot coverage for the withTarget
modifier that verifies both AudioUploader.swift and SampleUploader.swift are
copied and registered via addSourceFile in the expected Xcode target build
phase. Use the existing plugin test conventions and assert the generated project
output so regressions in these static Swift source entries are detected.

Source: Path instructions

🤖 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/react-native-sdk/expo-config-plugin/static/AudioUploader.swift`:
- Around line 214-225: In the planar interleaving logic around frameCount and
output, derive frameCount from the minimum mDataByteSize across all buffers
rather than buffers[0], and return early when the clamped count is zero. Apply
this same change at
packages/react-native-sdk/expo-config-plugin/static/AudioUploader.swift:214-225
and sample-apps/react-native/dogfood/ios/Broadcast
Extension/AudioUploader.swift:214-225, preserving the existing channel/frame
copy behavior.
- Around line 34-49: Serialize updates to dataToSend and byteIndex by moving
their assignments into the serialQueue.async block immediately before
sendDataChunk(), while preserving the existing readiness and return behavior.
Apply this identical change in
packages/react-native-sdk/expo-config-plugin/static/AudioUploader.swift lines
34-49 and sample-apps/react-native/dogfood/ios/Broadcast
Extension/AudioUploader.swift lines 34-49 so both AudioUploader copies
synchronize state mutations.

In `@packages/react-native-sdk/ios/StreamVideoReactNative.m`:
- Around line 686-689: Update the iOS screen-audio capture flow around
_screenAudioCapture to remove the stale non-existent reference: either provide a
valid shared Swift implementation and expose its new, onAudioBuffer, start, and
stop APIs through the React Native bridge, or mirror Android’s cleanup by
clearing the capture object after stopping it and recreating it through a valid
implementation.

---

Nitpick comments:
In
`@packages/react-native-sdk/expo-config-plugin/src/withIosScreenCapture/withTarget.ts`:
- Around line 182-189: Add unit-test or snapshot coverage for the withTarget
modifier that verifies both AudioUploader.swift and SampleUploader.swift are
copied and registered via addSourceFile in the expected Xcode target build
phase. Use the existing plugin test conventions and assert the generated project
output so regressions in these static Swift source entries are detected.

In `@packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift`:
- Around line 134-151: Update SampleHandler.swift at
packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift:134-151
and sample-apps/react-native/dogfood/ios/Broadcast
Extension/SampleHandler.swift:134-151 to store audio and video retry timers as
properties, extract their shared retry logic into one open-with-retry helper,
and cancel both timers from broadcastFinished so no retry continues after
teardown.
🪄 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 Plus

Run ID: 1460615c-ddb8-48dd-9ea0-4c6cfa02ac47

📥 Commits

Reviewing files that changed from the base of the PR and between 4fe5c40 and 156ed85.

📒 Files selected for processing (8)
  • packages/react-native-sdk/expo-config-plugin/src/withIosScreenCapture/withTarget.ts
  • packages/react-native-sdk/expo-config-plugin/static/AudioUploader.swift
  • packages/react-native-sdk/expo-config-plugin/static/SampleHandler.swift
  • packages/react-native-sdk/ios/StreamVideoReactNative.m
  • packages/react-native-sdk/src/hooks/useScreenShareButton.ts
  • sample-apps/react-native/dogfood/ios/Broadcast Extension/AudioUploader.swift
  • sample-apps/react-native/dogfood/ios/Broadcast Extension/SampleHandler.swift
  • sample-apps/react-native/dogfood/src/components/CallControls/BottomControls/index.tsx

Comment thread packages/react-native-sdk/expo-config-plugin/static/AudioUploader.swift Outdated
Comment thread packages/react-native-sdk/ios/StreamVideoReactNative.m
@greenfrvr
greenfrvr merged commit eb40f3e into main Aug 4, 2026
13 of 15 checks passed
@greenfrvr
greenfrvr deleted the feat/ios-broadcast-screenshare-audio branch August 4, 2026 16:21
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

🎉 The changes from this pull request have been released.

Shipped with:

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.

2 participants